diff --git a/packages/docs/docusaurus.config.js b/packages/docs/docusaurus.config.js index bcbd0cd2c3..e961d9ae71 100644 --- a/packages/docs/docusaurus.config.js +++ b/packages/docs/docusaurus.config.js @@ -4,6 +4,8 @@ const lightCodeTheme = require('prism-react-renderer/themes/github'); const darkCodeTheme = require('prism-react-renderer/themes/dracula'); +const currentProjectVersion = require('./package.json').version; + /** @type {import('@docusaurus/types').Config} */ const config = { title: 'react-jsonschema-form', @@ -44,9 +46,13 @@ const config = { lastVersion: 'current', versions: { current: { - label: 'v5', + label: `Current (v${currentProjectVersion})`, path: '', }, + '5.24.10': { + label: 'v5', + path: 'version-5.24.10', + }, '4.2.3': { label: 'v4', path: 'version-4.2.3', diff --git a/packages/docs/tsconfig.json b/packages/docs/tsconfig.json index 6f4756980d..aea83c96d6 100644 --- a/packages/docs/tsconfig.json +++ b/packages/docs/tsconfig.json @@ -2,6 +2,7 @@ // This file is not used in compilation. It is here just for a nice editor experience. "extends": "@tsconfig/docusaurus/tsconfig.json", "compilerOptions": { - "baseUrl": "." + "baseUrl": ".", + "resolveJsonModule": true } } diff --git a/packages/docs/versioned_docs/version-5.24.10/00-introduction.mdx b/packages/docs/versioned_docs/version-5.24.10/00-introduction.mdx new file mode 100644 index 0000000000..ec7b1078c8 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/00-introduction.mdx @@ -0,0 +1,135 @@ +--- +id: intro +title: Introduction +slug: / +--- + +# react-jsonschema-form + +![Build Status](https://github.com/rjsf-team/react-jsonschema-form/workflows/CI/badge.svg) + +A simple [React](https://reactjs.org/) component capable of building HTML forms out of a [JSON schema](http://json-schema.org/). + +A [live playground](https://rjsf-team.github.io/react-jsonschema-form/) is hosted on GitHub Pages: + + + Playground + + +## Philosophy + +react-jsonschema-form is meant to automatically generate a React form based on a [JSON Schema](http://json-schema.org/). If you want to generate a form for any data, sight unseen, simply given a JSON schema, react-jsonschema-form may be for you. If you have _a priori_ knowledge of your data and want a toolkit for generating forms for it, you might look elsewhere. + +react-jsonschema-form also comes with tools such as `uiSchema` and other form props to customize the look and feel of the form beyond the default themes. + +## Installation + +First install the dependencies from npm, along with a validator implementation (such as `@rjsf/validator-ajv8`): + +```bash +$ npm install @rjsf/core @rjsf/utils @rjsf/validator-ajv8 --save +``` + +Then import the dependencies as follows: + +```ts +import Form from '@rjsf/core'; +import validator from '@rjsf/validator-ajv8'; +``` + +Our latest version requires React 16+. + +## Usage + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Todo', + type: 'object', + required: ['title'], + properties: { + title: { type: 'string', title: 'Title', default: 'A new task' }, + done: { type: 'boolean', title: 'Done?', default: false }, + }, +}; + +const log = (type) => console.log.bind(console, type); + +render( +
, + document.getElementById('app') +); +``` + +## Theming + +For more information on what themes we support, see [Using Themes](usage/themes). + + + +## License + +Apache 2 + +## Credits + + + + + + + + + + + + + + +
+ mozilla-services-logo + + This project initially started as a mozilla-services project. +
+ browserstack logo + + Testing is powered by BrowserStack. +
+ netlify logo + + Deploy Previews are provided by Netlify. +
+ +## Who uses react-jsonschema-form? + +- ... + +Add your own company / organization by making a [pull request](https://github.com/rjsf-team/react-jsonschema-form/pulls). diff --git a/packages/docs/versioned_docs/version-5.24.10/01-quickstart.md b/packages/docs/versioned_docs/version-5.24.10/01-quickstart.md new file mode 100644 index 0000000000..e6c1050fe1 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/01-quickstart.md @@ -0,0 +1,163 @@ +# Quickstart + +Let's walk through setup of a form after installing the dependency properly. +NOTE: As of version 5, the `Form` now requires you to provide a `validator` implementation. We recommend the one from `@rjsf/validator-ajv8`. + +## Form schema + +First, specify a schema using the [JSON Schema specification](https://json-schema.org/). The below schema renders a single string field: + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Test form', + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +You can also render an object with multiple fields with the below schema: + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Test form', + type: 'object', + properties: { + name: { + type: 'string', + }, + age: { + type: 'number', + }, + }, +}; + +render(, document.getElementById('app')); +``` + +For more information and examples of JSON Schema properties that this library supports, see [Using JSON Schema](json-schema/single.md). + +## Form uiSchema + +The uiSchema is used to add more customization to the form's look and feel. Use the `classNames` +attribute of the uiSchema to add a custom CSS class name to the form: + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Test form', + type: 'string', +}; + +const uiSchema: UiSchema = { + 'ui:classNames': 'custom-css-class', +}; + +render(, document.getElementById('app')); +``` + +To customize object fields in the uiSchema, the structure of the +uiSchema should be `{key: value}`, where `key` is the property key and `value` is an +object with the uiSchema configuration for that particular property. For example: + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Test form', + type: 'object', + properties: { + name: { + type: 'string', + }, + age: { + type: 'number', + }, + }, +}; + +const uiSchema: UiSchema = { + name: { + 'ui:classNames': 'custom-class-name', + }, + age: { + 'ui:classNames': 'custom-class-age', + }, +}; + +render(, document.getElementById('app')); +``` + +## Form initialization + +Often you'll want to prefill a form with existing data; this is done by passing a `formData` prop object matching the schema: + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + title: { + type: 'string', + }, + done: { + type: 'boolean', + }, + }, +}; + +const formData = { + title: 'First task', + done: true, +}; + +render(, document.getElementById('app')); +``` + +> Note: If your form has a single field, pass a single value to `formData`. ex: `formData="Charlie"` + +> WARNING: If you have situations where your parent component can re-render, make sure you listen to the `onChange` event and update the data you pass to the `formData` attribute. + +### Form event handlers + +You can use event handlers such as `onChange`, `onError`, `onSubmit`, `onFocus`, and `onBlur` on the `` component; see the [Form Props Reference](./api-reference/form-props.md) for more details. + +### Controlled component + +By default, `` is an [uncontrolled component](https://reactjs.org/docs/uncontrolled-components.html). To make it a controlled component, use the +`onChange` and `formData` props as in the below example: + +```tsx +import Form from '@rjsf/core'; +import validator from '@rjsf/validator-ajv8'; + +const App = () => { + const [formData, setFormData] = React.useState(null); + return ( + setFormData(e.formData)} + validator={validator} + /> + ); +}; + +render(, document.getElementById('app')); +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-templates.md b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-templates.md new file mode 100644 index 0000000000..c2ecb0d11e --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-templates.md @@ -0,0 +1,1052 @@ +# Custom Templates + +This is an advanced feature that lets you customize even more aspects of the form: + +| | Custom Field | Custom Template | Custom Widget | +| --------------------- | ----------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------- | +| **What it does** | Overrides all behaviour | Overrides just the layout (not behaviour) | Overrides just the input box (not layout, labels, or help, or validation) | +| **Usage** | Global or per-field | Global or per-field | Global or per-field | +| **Global Example** | `` | `` | `` | +| **Per-Field Example** | `"ui:field": MyCustomField` | `"ui:ArrayFieldTemplate": MyArrayTemplate` | `"ui:widget":MyCustomWidget` | +| **Documentation** | [Custom Fields](custom-widgets-fields.md) | See documentation below | [Custom Widgets](custom-widgets-fields.md) | + +In version 5, all existing `templates` were consolidated into a new `TemplatesType` interface that is provided as part of the `Registry`. +They can also be overloaded globally on the `Form` via the `templates` prop as well as globally or per-field through the `uiSchema`. +Further, many new templates were added or repurposed from existing `widgets` and `fields` in an effort to simplify the effort needed by theme authors to build new and/or maintain current themes. +These new templates can also be overridden by individual users to customize the specific needs of their application. +A special category of templates, `ButtonTemplates`, were also added to support the easy replacement of the `Submit` button on the form, the `Add` and `Remove` buttons associated with `additionalProperties` on objects and elements of arrays, as well as the `Move up` and `Move down` buttons used for reordering arrays. +This category, unlike the others, can only be overridden globally via the `templates` prop on `Form`. + +Below is the table that lists all the `templates`, their props interface, their `uiSchema` name and from where they originated in the previous version of RJSF: + +| Template\* | Props Type | UiSchema name | Origin | +| ----------------------------------------------------------------- | ----------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [ArrayFieldTemplate](#arrayfieldtemplate) | ArrayFieldTemplateProps | ui:ArrayFieldTemplate | Formerly `Form.ArrayFieldTemplate` or `Registry.ArrayFieldTemplate` | +| [ArrayFieldDescriptionTemplate\*](#arrayfielddescriptiontemplate) | ArrayFieldDescriptionProps | ui:ArrayFieldDescriptionTemplate | Formerly part of `@rjsf/core` ArrayField, refactored as a template, used in all `ArrayFieldTemplate` implementations | +| [ArrayFieldItemTemplate\*](#arrayfielditemtemplate) | ArrayFieldTemplateItemType | ui:ArrayFieldItemTemplate | Formerly an internal class for `ArrayFieldTemplate`s in all themes, refactored as a template in each theme, used in all `ArrayFieldTemplate` implementations | +| [ArrayFieldTitleTemplate\*](#arrayfieldtitletemplate) | ArrayFieldTitleProps | ui:ArrayFieldTitleTemplate | Formerly part of `@rjsf/core` ArrayField, refactored as a template, used in all `ArrayFieldTemplate` implementations. | +| [BaseInputTemplate\*](#baseinputtemplate) | WidgetProps | ui:BaseInputTemplate | Formerly a `widget` in `@rjsf.core` moved to `templates` and newly implemented in each theme to maximize code reuse. | +| [DescriptionFieldTemplate\*](#descriptionfieldtemplate) | DescriptionFieldProps | ui:DescriptionFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. Previously implemented in each theme. | +| [ErrorListTemplate\*](#errorlisttemplate) | ErrorListProps | ui:ErrorListTemplate | Formerly `Form.ErrorList` moved to `templates` with the `Templates` suffix. Previously implemented in each theme. | +| [FieldErrorTemplate\*](#fielderrortemplate) | FieldErrorProps | ui:FieldErrorTemplate | Formerly internal `ErrorList` component accessible only to `SchemaField` | +| [FieldHelpTemplate\*](#fieldhelptemplate) | FieldHelpProps | ui:FieldHelpTemplate | Formerly internal `Help` component accessible only to `SchemaField` | +| [FieldTemplate](#fieldtemplate) | FieldTemplateProps | ui:FieldTemplate | Formerly `Form.FieldTemplate` or `Registry.FieldTemplate` | +| [ObjectFieldTemplate](#objectfieldtemplate) | ObjectFieldTemplateProps | ui:ObjectFieldTemplate | Formerly `Form.ObjectFieldTemplate` or `Registry.ObjectFieldTemplate` | +| [TitleFieldTemplate\*](#titlefieldtemplate) | TitleFieldProps | ui:TitleFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. Previously implemented in each theme. | +| [UnsupportedFieldTemplate\*](#unsupportedfieldtemplate) | UnsupportedFieldProps | ui:UnsupportedFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. | +| [WrapIfAdditionalTemplate\*](#wrapifadditionaltemplate) | WrapIfAdditionalTemplateProps | ui:WrapIfAdditionalTemplate | Formerly an internal component in `@rjsf.core`. Previously implemented in most themes. | +| [ButtonTemplates.AddButton\*](#addbutton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.MoveDownButton\*](#movedownbutton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.MoveUpButton\*](#moveupbutton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.RemoveButton\*](#removebutton) | IconButtonProps | n/a | Formerly an internal implementation in each theme | +| [ButtonTemplates.SubmitButton\*](#submitbutton) | SubmitButtonProps | n/a | Formerly a `field` in each theme move to `templates.ButtonTemplates` | + +\* indicates a new template in version 5 + +## ArrayFieldTemplate + +You can use an `ArrayFieldTemplate` to customize how your arrays are rendered. +This allows you to customize your array, and each element in the array. +If you only want to customize how the array's title, description or how the array items are presented, you may want to consider providing your own [ArrayFieldDescriptionTemplate](#arrayfielddescriptiontemplate), [ArrayFieldItemTemplate](#arrayfielditemtemplate) and/or [ArrayFieldTitleTemplate](#arrayfieldtitletemplate) instead. +You can also customize arrays by specifying a widget in the relevant `ui:widget` schema, more details over on [Custom Widgets](../json-schema/arrays.md#custom-widgets). + +```tsx +import { ArrayFieldTemplateProps, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +function ArrayFieldTemplate(props: ArrayFieldTemplateProps) { + return ( +
+ {props.items.map((element) => element.children)} + {props.canAdd && } +
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +You also can provide your own field template to a uiSchema by specifying a `ui:ArrayFieldTemplate` property. + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:ArrayFieldTemplate': ArrayFieldTemplate, +}; +``` + +Please see the [customArray.tsx sample](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/playground/src/samples/customArray.tsx) from the [playground](https://rjsf-team.github.io/react-jsonschema-form/) for another example. + +The following props are passed to each `ArrayFieldTemplate`: + +- `canAdd`: A boolean value stating whether new elements can be added to the array. +- `className`: The className string. +- `disabled`: A boolean value stating if the array is disabled. +- `idSchema`: An object containing the id for this object & ids for its properties +- `items`: An array of objects representing the items in the array. Each of the items represent a child with properties described below. +- `onAddClick: (event?) => void`: A function that adds a new item to the array. +- `readonly`: A boolean value stating if the array is read-only. +- `required`: A boolean value stating if the array is required. +- `hideError`: A boolean value stating if the field is hiding its errors. +- `schema`: The schema object for this array. +- `uiSchema`: The uiSchema object for this array field. +- `title`: A string value containing the title for the array. +- `formContext`: The `formContext` object that you passed to Form. +- `formData`: The formData for this array. +- `errorSchema`: The optional validation errors for the array field and the items within it, in the form of an `ErrorSchema` +- `rawErrors`: An array of strings listing all generated error messages from encountered errors for this widget +- `registry`: The `registry` object. + +The following props are part of each element in `items`: + +- `children`: The html for the item's content. +- `className`: The className string. +- `disabled`: A boolean value stating if the array item is disabled. +- `hasCopy`: A boolean value stating whether the array item can be copied. +- `hasMoveDown`: A boolean value stating whether the array item can be moved down. +- `hasMoveUp`: A boolean value stating whether the array item can be moved up. +- `hasRemove`: A boolean value stating whether the array item can be removed. +- `hasToolbar`: A boolean value stating whether the array item has a toolbar. +- `index`: A number stating the index the array item occurs in `items`. +- `key`: A stable, unique key for the array item. +- `onAddIndexClick: (index) => (event?) => void`: Returns a function that adds a new item at `index`. +- `onDropIndexClick: (index) => (event?) => void`: Returns a function that removes the item at `index`. +- `onReorderClick: (index, newIndex) => (event?) => void`: Returns a function that swaps the items at `index` with `newIndex`. +- `readonly`: A boolean value stating if the array item is read-only. +- `uiSchema`: The uiSchema object for this array item. +- `registry`: The `registry` object. + +> Note: Array and object field templates are always rendered inside the FieldTemplate. To fully customize an array field template, you may need to specify both `ui:FieldTemplate` and `ui:ArrayFieldTemplate`. + +## ArrayFieldDescriptionTemplate + +The out-of-the-box version of this template will render the `DescriptionFieldTemplate` with a generated id, if there is a `description` otherwise nothing is rendered. +If you want different behavior for the rendering of the description of an array field, you can customize this template. +If you want a different behavior for the rendering of ALL descriptions in the `Form`, see [DescriptionFieldTemplate](#descriptionfieldtemplate) + +```tsx +import { ArrayFieldDescriptionProps, RJSFSchema, descriptionId } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +function ArrayFieldDescriptionTemplate(props: ArrayFieldDescriptionProps) { + const { description, idSchema } = props; + const id = descriptionId(idSchema); + return ( +
+ Description + {description} +
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:ArrayFieldDescriptionTemplate': ArrayFieldDescriptionTemplate, +}; +``` + +The following props are passed to each `ArrayFieldDescriptionTemplate`: + +- `description`: The description of the array field being rendered. +- `idSchema`: The idSchema of the array field in the hierarchy. +- `schema`: The schema object for this array field. +- `uiSchema`: The uiSchema object for this array field. +- `registry`: The `registry` object. + +## ArrayFieldItemTemplate + +The `ArrayFieldItemTemplate` is used to render the representation of a single item in an array. +All of the `ArrayFieldTemplate` implementations in all themes get this template from the `registry` in order to render array fields items. +Each theme has an implementation of the `ArrayFieldItemTemplate` to render an array field item in a manner best suited to the theme. +If you want to change how an array field item is rendered you can customize this template (for instance to remove the move up/down and remove buttons). + +```tsx +import { ArrayFieldTemplateItemType, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +function ArrayFieldItemTemplate(props: ArrayFieldTemplateItemType) { + const { children, className } = props; + return
{children}
; +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to each `ArrayFieldItemTemplate`: + +- `children`: The html for the item's content. +- `className`: The className string. +- `disabled`: A boolean value stating if the array item is disabled. +- `canAdd`: A boolean value stating whether new items can be added to the array. +- `hasCopy`: A boolean value stating whether the array item can be copied. +- `hasMoveDown`: A boolean value stating whether the array item can be moved down. +- `hasMoveUp`: A boolean value stating whether the array item can be moved up. +- `hasRemove`: A boolean value stating whether the array item can be removed. +- `hasToolbar`: A boolean value stating whether the array item has a toolbar. +- `index`: A number stating the index the array item occurs in `items`. +- `totalItems`: A number stating the total number `items` in the array. +- `key`: A stable, unique key for the array item. +- `onAddIndexClick: (index) => (event?) => void`: Returns a function that adds a new item at `index`. +- `onCopyIndexClick: (index) => (event?) => void`: Returns a function that copies the item at `index` into the position at `index + 1` +- `onDropIndexClick: (index) => (event?) => void`: Returns a function that removes the item at `index`. +- `onReorderClick: (index, newIndex) => (event?) => void`: Returns a function that swaps the items at `index` with `newIndex`. +- `readonly`: A boolean value stating if the array item is read-only. +- `schema`: The schema object for this array item. +- `uiSchema`: The uiSchema object for this array item. +- `registry`: The `registry` object. + +## ArrayFieldTitleTemplate + +The out-of-the-box version of this template will render the `TitleFieldTemplate` with a generated id, if there is a `title` otherwise nothing is rendered. +If you want a different behavior for the rendering of the title of an array field, you can customize this template. +If you want a different behavior for the rendering of ALL titles in the `Form`, see [TitleFieldTemplate](#titlefieldtemplate) + +```tsx +import { ArrayFieldTitleTemplateProps, RJSFSchema, titleId } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +function ArrayFieldTitleTemplate(props: ArrayFieldTitleProps) { + const { title, idSchema } = props; + const id = titleId(idSchema); + return

{title}

; +} + +render( + , + document.getElementById('app') +); +``` + +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:ArrayFieldTitleTemplate': ArrayFieldTitleTemplate, +}; +``` + +The following props are passed to each `ArrayFieldTitleTemplate`: + +- `title`: The title of the array field being rendered. +- `idSchema`: The idSchema of the array field in the hierarchy. +- `schema`: The schema object for this array field. +- `uiSchema`: The uiSchema object for this array field. +- `required`: A boolean value stating if the field is required +- `registry`: The `registry` object. + +## BaseInputTemplate + +The `BaseInputTemplate` is the template to use to render the basic `` component for a theme. +It is used as the template for rendering many of the `` based widgets that differ by `type` and callbacks only. +For example, the `TextWidget` implementation in `core` is simply a wrapper around `BaseInputTemplate` that it gets from the `registry`. +Additionally, each theme implements its own version of `BaseInputTemplate` without needing to provide a different implementation of `TextWidget`. + +If you desire a different implementation for the `` based widgets, you can customize this template. +For instance, say you have a `CustomTextInput` component that you want to integrate: + +```tsx +import { ChangeEvent, FocusEvent } from 'react'; +import { getInputProps, RJSFSchema, BaseInputTemplateProps } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +import CustomTextInput from '../CustomTextInput'; + +const schema: RJSFSchema = { + type: 'string', + title: 'My input', + description: 'input description', +}; + +function BaseInputTemplate(props: BaseInputTemplateProps) { + const { + schema, + id, + options, + label, + value, + type, + placeholder, + required, + disabled, + readonly, + autofocus, + onChange, + onChangeOverride, + onBlur, + onFocus, + rawErrors, + hideError, + uiSchema, + registry, + formContext, + ...rest + } = props; + const onTextChange = ({ target: { value: val } }: ChangeEvent) => { + // Use the options.emptyValue if it is specified and newVal is also an empty string + onChange(val === '' ? options.emptyValue || '' : val); + }; + const onTextBlur = ({ target: { value: val } }: FocusEvent) => onBlur(id, val); + const onTextFocus = ({ target: { value: val } }: FocusEvent) => onFocus(id, val); + + const inputProps = { ...rest, ...getInputProps(schema, type, options) }; + const hasError = rawErrors.length > 0 && !hideError; + + return ( + + ); +} + +render( + , + document.getElementById('app') +); +``` + +### Wrapping BaseInputTemplate to customize it + +Sometimes you just need to pass some additional properties to the existing `BaseInputTemplate`. +The way to do this varies based upon whether you are using `core` or some other theme (such as `mui`): + +```tsx +import { BaseInputTemplateProps } from '@rjsf/utils'; +import { getDefaultRegistry } from '@rjsf/core'; +import { Templates } from '@rjsf/mui'; + +const { + templates: { BaseInputTemplate }, +} = getDefaultRegistry(); // To get templates from core +// const { BaseInputTemplate } = Templates; // To get templates from a theme do this + +function MyBaseInputTemplate(props: BaseInputTemplateProps) { + const customProps = {}; + // get your custom props from where you need to + return ; +} +``` + +The following props are passed to the `BaseInputTemplate`: + +- `id`: The generated id for this widget; +- `schema`: The JSONSchema subschema object for this widget; +- `uiSchema`: The uiSchema for this widget; +- `value`: The current value for this widget; +- `placeholder`: The placeholder for the widget, if any; +- `required`: The required status of this widget; +- `disabled`: A boolean value stating if the widget is disabled; +- `hideError`: A boolean value stating if the widget is hiding its errors. +- `readonly`: A boolean value stating if the widget is read-only; +- `autofocus`: A boolean value stating if the widget should autofocus; +- `label`: The computed label for this widget, as a string +- `multiple`: A boolean value stating if the widget can accept multiple values; +- `onChange`: The value change event handler; call it with the new value every time it changes; +- `onChangeOverride`: A `BaseInputTemplate` implements a default `onChange` handler that it passes to the HTML input component to handle the `ChangeEvent`. Sometimes a widget may need to handle the `ChangeEvent` using custom logic. If that is the case, that widget should provide its own handler via this prop; +- `onKeyChange`: The key change event handler (only called for fields with `additionalProperties`); pass the new value every time it changes; +- `onBlur`: The input blur event handler; call it with the widget id and value; +- `onFocus`: The input focus event handler; call it with the widget id and value; +- `options`: A map of options passed as a prop to the component (see [Custom widget options](./custom-widgets-fields.md#custom-widget-options)). +- `options.enumOptions`: For enum fields, this property contains the list of options for the enum as an array of { label, value } objects. If the enum is defined using the oneOf/anyOf syntax, the entire schema object for each option is appended onto the { schema, label, value } object. +- `formContext`: The `formContext` object that you passed to `Form`. +- `rawErrors`: An array of strings listing all generated error messages from encountered errors for this widget. +- `registry`: The `registry` object + +## DescriptionFieldTemplate + +Each theme implements a `DescriptionFieldTemplate` used to render the description of a field. +If you want to customize how descriptions are rendered you can. + +```tsx +import { DescriptionFieldProps, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + title: 'My input', + description: 'input description', +}; + +function DescriptionFieldTemplate(props: DescriptionFieldProps) { + const { description, id } = props; + return ( +
+ Description + {description} +
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to the `DescriptionFieldTemplate`: + +- `description`: The description of the field being rendered. +- `id`: The id of the field in the hierarchy. +- `schema`: The schema object for the field. +- `uiSchema`: The uiSchema object for the field. +- `registry`: The `registry` object. + +## ErrorListTemplate + +The `ErrorListTemplate` is the template that renders the all the errors associated with the fields in the `Form`, at the top. +Each theme implements a `ErrorListTemplate` used to render its errors using components for the theme's toolkit. +If you want to customize how all the errors are rendered you can. + +```tsx +import { ErrorListProps, RJSFValidationError, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + title: 'My input', + description: 'input description', +}; + +function ErrorListTemplate(props: ErrorListProps) { + const { errors } = props; + return ( +
+ Errors +
    + {errors.map((error: RJSFValidationError, i: number) => { + return ( +
  • + {error.stack} +
  • + ); + })} +
+
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to the `ErrorListTemplate`: + +- `schema`: The schema that was passed to `Form` +- `uiSchema`: The uiSchema that was passed to `Form` +- `formContext`: The `formContext` object that you passed to `Form`. +- `errors`: An array of all errors in this `Form`. +- `errorSchema`: The `ErrorSchema` constructed by `Form` + +## FieldErrorTemplate + +The `FieldErrorTemplate` is the template that renders all the errors associated a single field. +If you want to customize how the errors are rendered you can. + +```tsx +import { FieldErrorProps, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + title: 'My input', + description: 'input description', +}; + +function FieldErrorTemplate(props: FieldErrorProps) { + const { errors } = props; + return ( +
+ Errors +
    + {errors.map((error: string, i: number) => { + return ( +
  • + {error.stack} +
  • + ); + })} +
+
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to the `FieldErrorTemplate`: + +- `schema`: The schema for the field +- `uiSchema`: The uiSchema for the field +- `idSchema`: An object containing the id for this field & ids for its properties. +- `errors`: An array of all errors for this field +- `errorSchema`: The `ErrorSchema` for this field +- `registry`: The `Registry` object + +## FieldHelpTemplate + +The `FieldHelpTemplate` is the template that renders the help associated a single field. +If you want to customize how the help is rendered you can. + +```tsx +import { FieldHelpProps, RJSFSchema, helpId } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + title: 'My input', + description: 'input description', +}; + +function FieldHelpTemplate(props: FieldHelpProps) { + const { help, idSchema } = props; + const id = helpId(idSchema); + return ; +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to the `FieldHelpTemplate`: + +- `schema`: The schema for the field +- `uiSchema`: The uiSchema for the field +- `idSchema`: An object containing the id for this field & ids for its properties. +- `help`: The help information to be rendered +- `registry`: The `Registry` object + +## FieldTemplate + +To take control over the inner organization of each field (each form row), you can define a _field template_ for your form. + +A field template is basically a React stateless component being passed field-related props, allowing you to structure your form row as you like. + +```tsx +import { FieldTemplateProps, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +function CustomFieldTemplate(props: FieldTemplateProps) { + const { id, classNames, style, label, help, required, description, errors, children } = props; + return ( +
+ + {description} + {children} + {errors} + {help} +
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +You also can provide your own field template to a uiSchema by specifying a `ui:FieldTemplate` property. + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:FieldTemplate': CustomFieldTemplate, +}; +``` + +If you want to handle the rendering of each element yourself, you can use the props `rawHelp`, `rawDescription` and `rawErrors`. + +The following props are passed to a custom field template component: + +- `id`: The id of the field in the hierarchy. You can use it to render a label targeting the wrapped widget. +- `classNames`: A string containing the base Bootstrap CSS classes, merged with any [custom ones](../api-reference/uiSchema.md#classnames) defined in your uiSchema. +- `style`: An object containing the `StyleHTMLAttributes` defined in the `uiSchema`. +- `label`: The computed label for this field, as a string. +- `description`: A component instance rendering the field description, if one is defined (this will use any [custom `DescriptionFieldTemplate`](#descriptionfieldtemplate) defined in the `templates` passed to the `Form`). +- `rawDescription`: A string containing any `ui:description` uiSchema directive defined. +- `children`: The field or widget component instance for this field row. +- `errors`: A component instance listing any encountered errors for this field. +- `rawErrors`: An array of strings listing all generated error messages from encountered errors for this field. +- `help`: A component instance rendering any `ui:help` uiSchema directive defined. +- `rawHelp`: A string containing any `ui:help` uiSchema directive defined. **NOTE:** `rawHelp` will be `undefined` if passed `ui:help` is a React component instead of a string. +- `hidden`: A boolean value stating if the field should be hidden. +- `required`: A boolean value stating if the field is required. +- `readonly`: A boolean value stating if the field is read-only. +- `hideError`: A boolean value stating if the field is hiding its errors +- `disabled`: A boolean value stating if the field is disabled. +- `displayLabel`: A boolean value stating if the label should be rendered or not. This is useful for nested fields in arrays where you don't want to clutter the UI. +- `schema`: The schema object for this field. +- `uiSchema`: The uiSchema object for this field. +- `onChange`: The value change event handler; Can be called with a new value to change the value for this field. +- `formContext`: The `formContext` object that you passed to `Form`. +- `formData`: The formData for this field. +- `registry`: The `registry` object. + +> Note: you can only define a single global field template for a form, but you can set individual field templates per property using `"ui:FieldTemplate"`. + +## ObjectFieldTemplate + +```tsx +import { ObjectFieldTemplateProps, RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + title: 'Object title', + description: 'Object description', + properties: { + name: { + type: 'string', + }, + age: { + type: 'number', + }, + }, +}; + +function ObjectFieldTemplate(props: ObjectFieldTemplateProps) { + return ( +
+ {props.title} + {props.description} + {props.properties.map((element) => ( +
{element.content}
+ ))} +
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +You also can provide your own field template to a uiSchema by specifying a `ui:ObjectFieldTemplate` property. + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:ObjectFieldTemplate': ObjectFieldTemplate, +}; +``` + +Please see the [customObject.tsx sample](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/playground/src/samples/customObject.tsx) from the [playground](https://rjsf-team.github.io/react-jsonschema-form/) for a better example. + +The following props are passed to each `ObjectFieldTemplate` as defined by the `ObjectFieldTemplateProps` in `@rjsf/utils`: + +- `title`: A string value containing the title for the object. +- `description`: A string value containing the description for the object. +- `disabled`: A boolean value stating if the object is disabled. +- `properties`: An array of object representing the properties in the object. Each of the properties represent a child with properties described below. +- `onAddClick: (schema: RJSFSchema) => () => void`: Returns a function that adds a new property to the object (to be used with additionalProperties) +- `readonly`: A boolean value stating if the object is read-only. +- `required`: A boolean value stating if the object is required. +- `hideError`: A boolean value stating if the field is hiding its errors. +- `schema`: The schema object for this object. +- `uiSchema`: The uiSchema object for this object field. +- `idSchema`: An object containing the id for this object & ids for its properties. +- `errorSchema`: The optional validation errors in the form of an `ErrorSchema` +- `formData`: The form data for the object. +- `formContext`: The `formContext` object that you passed to Form. +- `registry`: The `registry` object. + +The following props are part of each element in `properties`: + +- `content`: The html for the property's content. +- `name`: A string representing the property name. +- `disabled`: A boolean value stating if the object property is disabled. +- `readonly`: A boolean value stating if the property is read-only. +- `hidden`: A boolean value stating if the property should be hidden. + +> Note: Array and object field templates are always rendered inside the FieldTemplate. To fully customize an object field template, you may need to specify both `ui:FieldTemplate` and `ui:ObjectFieldTemplate`. + +## TitleFieldTemplate + +Each theme implements a `TitleFieldTemplate` used to render the title of a field. +If you want to customize how titles are rendered you can. + +```tsx +import { RJSFSchema, TitleFieldProps } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + title: 'My input', + description: 'input description', +}; + +function TitleFieldTemplate(props: TitleFieldProps) { + const { id, required, title } = props; + return ( +
+ {title} + {required && *} +
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to each `TitleFieldTemplate`: + +- `id`: The id of the field in the hierarchy. +- `title`: The title of the field being rendered. +- `schema`: The schema object for the field. +- `uiSchema`: The uiSchema object for the field. +- `required`: A boolean value stating if the field is required +- `registry`: The `registry` object. + +## UnsupportedFieldTemplate + +The `UnsupportedField` component is used to render a field in the schema is one that is not supported by react-jsonschema-form. +If you want to customize how an unsupported field is rendered (perhaps for localization purposes) you can. + +```tsx +import { RJSFSchema, UnsupportedFieldProps } from '@rjsf/utils'; +import { FormattedMessage } from 'react-intl'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'invalid', +}; + +function UnsupportedFieldTemplate(props: UnsupportedFieldProps) { + const { schema, reason } = props; + return ( +
+ +
{JSON.stringify(schema, null, 2)}
+
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to each `UnsupportedFieldTemplate`: + +- `schema`: The schema object for this unsupported field. +- `idSchema`: An object containing the id for this unsupported field. +- `reason`: The reason why the schema field has an unsupported type. +- `registry`: The `registry` object. + +## WrapIfAdditionalTemplate + +The `WrapIfAdditionalTemplate` is used by the `FieldTemplate` to conditionally render additional controls if `additionalProperties` is present in the schema. +You may customize `WrapIfAdditionalTemplate` if you wish to change the layout or behavior of user-controlled `additionalProperties`. + +```tsx +import { RJSFSchema, WrapIfAdditionalTemplateProps } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + additionalProperties: true, +}; + +function WrapIfAdditionalTemplate(props: WrapIfAdditionalTemplateProps) { + const { id, label, onKeyChange, onDropPropertyClick, schema, children, uiSchema, registry, classNames, style } = + props; + const { RemoveButton } = registry.templates.ButtonTemplates; + const additional = ADDITIONAL_PROPERTY_FLAG in schema; + + if (!additional) { + return
{children}
; + } + + return ( +
+ + +
{children}
+ +
+ ); +} + +render( + , + document.getElementById('app') +); +``` + +The following props are passed to the `WrapIfAdditionalTemplate`: + +- `children`: The children of the component, typically specified by the `FieldTemplate`. + +- `id`: The id of the field in the hierarchy. You can use it to render a label targeting the wrapped widget. +- `classNames`: A string containing the base Bootstrap CSS classes, merged with any [custom ones](../api-reference/uiSchema.md#classnames) defined in your uiSchema. +- `style`: An object containing the `StyleHTMLAttributes` defined in the `uiSchema`. +- `label`: The computed label for this field, as a string. +- `required`: A boolean value stating if the field is required. +- `readonly`: A boolean value stating if the field is read-only. +- `disabled`: A boolean value stating if the field is disabled. +- `schema`: The schema object for this field. +- `uiSchema`: The uiSchema object for this field. +- `onKeyChange`: A function that, when called, changes the current property key to the specified value +- `onDropPropertyClick`: A function that, when called, removes the key from the formData. + +## ButtonTemplates + +There are several buttons that are potentially rendered in the `Form`. +Each of these buttons have been customized in the themes, and can be customized by you as well. +All but one of these buttons (i.e. the `SubmitButton`) are rendered currently as icons with title text for a description. + +Each button template (except for the `SubmitButton`) accepts, as props, the standard [HTML button attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) along with the following: + +- `iconType`: An alternative specification for the type of the icon button. +- `icon`: The name representation or actual react element implementation for the icon. +- `uiSchema`: The uiSchema object for this field. +- `registry`: The `registry` object. + +### AddButton + +The `AddButton` is used to render an add action on a `Form` for both a new `additionalProperties` element for an object or a new element in an array. +You can customize the `AddButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from 'react'; +import { IconButtonProps, RJSFSchema } from '@rjsf/utils'; +import { FormattedMessage } from 'react-intl'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +function AddButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +} + +render( + , + document.getElementById('app') +); +``` + +### MoveDownButton + +The `MoveDownButton` is used to render a move down action on a `Form` for elements in an array. +You can customize the `MoveDownButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from 'react'; +import { IconButtonProps, RJSFSchema } from '@rjsf/utils'; +import { FormattedMessage } from 'react-intl'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +function MoveDownButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +} + +render( + , + document.getElementById('app') +); +``` + +### MoveUpButton + +The `MoveUpButton` is used to render a move up action on a `Form` for elements in an array. +You can customize the `MoveUpButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from 'react'; +import { IconButtonProps, RJSFSchema } from '@rjsf/utils'; +import { FormattedMessage } from 'react-intl'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +function MoveUpButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +} + +render( + , + document.getElementById('app') +); +``` + +### RemoveButton + +The `RemoveButton` is used to render a remove action on a `Form` for both a existing `additionalProperties` element for an object or an existing element in an array. +You can customize the `RemoveButton` to render something other than the icon button that is provided by a theme as follows: + +```tsx +import React from 'react'; +import { IconButtonProps, RJSFSchema } from '@rjsf/utils'; +import { FormattedMessage } from 'react-intl'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +function RemoveButton(props: IconButtonProps) { + const { icon, iconType, ...btnProps } = props; + return ( + + ); +} + +render( + , + document.getElementById('app') +); +``` + +### SubmitButton + +The `SubmitButton` is already very customizable via the `UISchemaSubmitButtonOptions` capabilities in the `uiSchema` but it can also be fully customized as you see fit. + +> NOTE: However you choose to implement this, making it something other than a `submit` type `button` may result in the `Form` not submitting when pressed. +> You could also choose to provide your own submit button as the [children prop](../api-reference/form-props.md#children) of the `Form` should you so choose. + +```tsx +import React from 'react'; +import { getSubmitButtonOptions, RJSFSchema, SubmitButtonProps } from '@rjsf/utils'; +import { FormattedMessage } from 'react-intl'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +function SubmitButton(props: SubmitButtonProps) { + const { uiSchema } = props; + const { norender } = getSubmitButtonOptions(uiSchema); + if (norender) { + return null; + } + return ( + + ); +} + +render( + , + document.getElementById('app') +); +``` + +The following prop is passed to a `SubmitButton`: + +- `uiSchema`: The uiSchema object for this field, used to extract the `UISchemaSubmitButtonOptions`. +- `registry`: The `registry` object. diff --git a/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-themes.md b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-themes.md new file mode 100644 index 0000000000..374a37ab7b --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-themes.md @@ -0,0 +1,117 @@ +# Custom Themes + +The `withTheme` component provides an easy way to extend the functionality of react-jsonschema-form by passing in a theme object that defines custom/overridden widgets and fields, as well as any of the other possible properties of the standard rjsf `Form` component. +This theme-defining object is passed as the only parameter to the HOC (`withTheme(ThemeObj)`), and the HOC will return a themed-component which you use instead of the standard `Form` component. + +## Usage + +```tsx +import React, { Component } from 'react'; +import validator from '@rjsf/validator-ajv8'; +import { withTheme, ThemeProps } from '@rjsf/core'; + +const theme: ThemeProps = { widgets: { test: () =>
test
} }; + +const ThemedForm = withTheme(theme); + +const Demo = () => ; +``` + +## Theme object properties + +The Theme object consists of the same properties as the rjsf `Form` component (such as **widgets**, **fields** and **templates**). +The themed-Form component merges together any theme-specific **widgets**, **fields** and **templates** with the default **widgets**, **fields** and **templates**. +For instance, providing a single widget in **widgets** will merge this widget with all the default widgets of the rjsf `Form` component, but overrides the default if the theme's widget's name matches the default widget's name. +Thus, for each default widget or field not specified/overridden, the themed-form will rely on the defaults from the rjsf `Form`. +Note that you are not required to pass in either custom **widgets**, **fields** or **templates** when using the custom-themed HOC component; +you can essentially redefine the default Form by simply doing `const Form = withTheme({});`. + +### Widgets and fields + +**widgets** and **fields** should be in the same format as shown [here](./custom-widgets-fields.md). + +Example theme with custom widget: + +```tsx +import { WidgetProps, RegistryWidgetsType } from '@rjsf/utils'; +import { ThemeProps } from '@rjsf/core'; + +const MyCustomWidget = (props: WidgetProps) => { + return ( + props.onChange(event.target.value)} + /> + ); +}; + +const myWidgets: RegistryWidgetsType = { + myCustomWidget: MyCustomWidget, +}; + +const ThemeObject: ThemeProps = { widgets: myWidgets }; +export default ThemeObject; +``` + +The above can be similarly done for **fields** and **templates**. + +### Templates + +Each template should be passed into the theme object via the **templates** object just as you would into the rjsf Form component. Here is an example of how to use a custom [ArrayFieldTemplate](./custom-templates.md#arrayfieldtemplate) and [ErrorListTemplate](./custom-templates.md#errorlisttemplate) in the theme object: + +```tsx +import { ArrayFieldTemplateProps, ErrorListProps } from '@rjsf/utils'; +import { ThemeProps } from '@rjsf/core'; + +function MyArrayFieldTemplate(props: ArrayFieldTemplateProps) { + return ( +
+ {props.items.map((element) => element.children)} + {props.canAdd && } +
+ ); +} + +function MyErrorListTemplate(props: ErrorListProps) { + const { errors } = props; + return ( +
    + {errors.map((error) => ( +
  • {error.stack}
  • + ))} +
+ ); +} + +const ThemeObject: ThemeProps = { + templates: { + ArrayFieldTemplate: MyArrayFieldTemplate, + ErrorListTemplate: MyErrorListTemplate, + }, + widgets: myWidgets, +}; + +export default ThemeObject; +``` + +## Overriding other Form props + +Just as the theme can override **widgets**, **fields**, any of the **templates**, and set default values to properties like **showErrorList**, you can do the same with the instance of the withTheme() Form component. + +```tsx +import { ThemeProps } from '@rjsf/core'; + +const ThemeObject: ThemeProps = { + templates: { + ArrayFieldTemplate: MyArrayFieldTemplate, + }, + fields: myFields, + showErrorList: false, + widgets: myWidgets, +}; +``` + +Thus, the user has higher priority than the withTheme HOC, and the theme has higher priority than the default values of the rjsf Form component (**User** > **Theme** > **Defaults**). diff --git a/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-widgets-fields.md b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-widgets-fields.md new file mode 100644 index 0000000000..628752fee8 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/custom-widgets-fields.md @@ -0,0 +1,547 @@ +# Custom Widgets and Fields + +The API allows to specify your own custom _widget_ and _field_ components: + +- A _widget_ represents a HTML tag for the user to enter data, eg. `input`, `select`, etc. +- A _field_ usually wraps one or more widgets and most often handles internal field state; think of a field as a form row, including the labels. + +## Customizing the default fields and widgets + +You can override any default field and widget, including the internal widgets like the `CheckboxWidget` that `BooleanField` renders for boolean values. You can override any field and widget just by providing the customized fields/widgets in the `fields` and `widgets` props: + +```tsx +import { RJSFSchema, UiSchema, WidgetProps, RegistryWidgetsType } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'boolean', + default: true, +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'checkbox', +}; + +const CustomCheckbox = function (props: WidgetProps) { + return ( + + ); +}; + +const widgets: RegistryWidgetsType = { + CheckboxWidget: CustomCheckbox, +}; + +render( + , + document.getElementById('app') +); +``` + +This allows you to create a reusable customized form class with your custom fields and widgets: + +```tsx +import { RegistryFieldsType, RegistryWidgetsType } from '@rjsf/utils'; +import { FormProps } from '@rjsf/core'; + +const customFields: RegistryFieldsType = { StringField: CustomString }; +const customWidgets: RegistryWidgetsType = { CheckboxWidget: CustomCheckbox }; + +function MyForm(props: FormProps) { + return ; +} +``` + +The default fields you can override are: + +- `ArrayField` +- `ArraySchemaField` +- `BooleanField` +- `DescriptionField` +- `OneOfField` +- `AnyOfField` +- `NullField` +- `NumberField` +- `ObjectField` +- `SchemaField` +- `StringField` +- `TitleField` +- `UnsupportedField` + +The default widgets you can override are: + +- `AltDateTimeWidget` +- `AltDateWidget` +- `CheckboxesWidget` +- `CheckboxWidget` +- `ColorWidget` +- `DateTimeWidget` +- `DateWidget` +- `EmailWidget` +- `FileWidget` +- `HiddenWidget` +- `PasswordWidget` +- `RadioWidget` +- `RangeWidget` +- `SelectWidget` +- `TextareaWidget` +- `TextWidget` +- `TimeWidget` +- `UpDownWidget` +- `URLWidget` + +## Raising errors from within a custom widget or field + +You can raise custom 'live validation' errors by overriding the `onChange` method to provide feedback while users are actively changing the form data. +Note that these errors are temporary and are not recognized during the form validation process. + +:::warning + +This method of raising errors _only_ runs during `onChange`, i.e. when the user is changing data. This will not catch errors `onSubmit`, i.e when submitting the form. +If you wish to add generic validation logic for your component, you should use the [`customValidate` Form prop](../api-reference/form-props.md#customvalidate). + +::: + +```tsx +import { ErrorSchema, RJSFSchema, UiSchema, WidgetProps, RegistryWidgetsType } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'text', + default: 'hello', +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'text', +}; + +const CustomTextWidget = function (props: WidgetProps) { + const { id, value } = props; + const raiseErrorOnChange = ({ target: { value } }: ChangeEvent) => { + let raiseError: ErrorSchema | undefined; + if (value !== 'test') { + raiseError = { + __errors: ['Value must be "test"'], + }; + } + props.onChange(value, raiseError, id); + }; + + return ; +}; + +const widgets: RegistryWidgetsType = { + TextWidget: CustomTextWidget, +}; + +render( + , + document.getElementById('app') +); +``` + +This creates a custom text widget that raises an error if the input value does not match 'test'. + +## Adding your own custom widgets + +You can provide your own custom widgets to a uiSchema for the following json data types: + +- `string` +- `number` +- `integer` +- `boolean` +- `array` + +```tsx +import { RJSFSchema, UiSchema, WidgetProps } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: Schema = { + type: 'string', +}; + +const uiSchema: UiSchema = { + 'ui:widget': (props: WidgetProps) => { + return ( + props.onChange(event.target.value)} + /> + ); + }, +}; + +render(, document.getElementById('app')); +``` + +The following props are passed to custom widget components: + +- `id`: The generated id for this widget, used to provide unique `name`s and `id`s for the HTML field elements rendered by widgets; +- `name`: The unique name of the field, usually derived from the name of the property in the JSONSchema; Provided in support of custom widgets; +- `schema`: The JSONSchema subschema object for this widget; +- `uiSchema`: The uiSchema for this widget; +- `value`: The current value for this widget; +- `placeholder`: The placeholder for the widget, if any; +- `required`: The required status of this widget; +- `disabled`: A boolean value stating if the widget is disabled; +- `readonly`: A boolean value stating if the widget is read-only; +- `autofocus`: A boolean value stating if the widget should autofocus; +- `label`: The computed label for this widget, as a string +- `hideLabel`: A boolean value, if true, will cause the label to be hidden. This is useful for nested fields where you don't want to clutter the UI. Customized via `label` in the `UiSchema`; +- `multiple`: A boolean value stating if the widget can accept multiple values; +- `onChange`: The value change event handler; call it with the new value every time it changes; +- `onKeyChange`: The key change event handler (only called for fields with `additionalProperties`); pass the new value every time it changes; +- `onBlur`: The input blur event handler; call it with the widget id and value; +- `onFocus`: The input focus event handler; call it with the widget id and value; +- `options`: A map of options passed as a prop to the component (see [Custom widget options](#custom-widget-options)). +- `options.enumOptions`: For enum fields, this property contains the list of options for the enum as an array of { label, value } objects. If the enum is defined using the oneOf/anyOf syntax, the entire schema object for each option is appended onto the { schema, label, value } object. +- `formContext`: The `formContext` object that you passed to `Form`. +- `rawErrors`: An array of strings listing all generated error messages from encountered errors for this widget. +- `registry`: A [registry](#the-registry-object) object (read next). + +### Custom component registration + +Alternatively, you can register them all at once by passing the `widgets` prop to the `Form` component, and reference their identifier from the `uiSchema`: + +```tsx +import { RJSFSchema, UiSchema, WidgetProps, RegistryWidgetsType } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const MyCustomWidget = (props: WidgetProps) => { + return ( + props.onChange(event.target.value)} + /> + ); +}; + +const widgets: RegistryWidgetsType = { + myCustomWidget: MyCustomWidget, +}; + +const schema: RJSFSchema = { + type: 'string', +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'myCustomWidget', +}; + +render( + , + document.getElementById('app') +); +``` + +This is useful if you expose the `uiSchema` as pure JSON, which can't carry functions. + +### Custom widget options + +If you need to pass options to your custom widget, you can add a `ui:options` object containing those properties. If the widget has `defaultProps`, the options will be merged with the (optional) options object from `defaultProps`: + +```tsx +import { RJSFSchema, UiSchema, WidgetProps } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +function MyCustomWidget(props: WidgetProps) { + const { options } = props; + const { color, backgroundColor } = options; + return ; +} + +MyCustomWidget.defaultProps = { + options: { + color: 'red', + }, +}; + +const uiSchema: UiSchema = { + 'ui:widget': MyCustomWidget, + 'ui:options': { + backgroundColor: 'yellow', + }, +}; + +// renders red on yellow input +render(, document.getElementById('app')); +``` + +> Note: This also applies to [registered custom components](#custom-component-registration). + +> Note: Since v0.41.0, the `ui:widget` object API, where a widget and options were specified with `"ui:widget": {component, options}` shape, is deprecated. It will be removed in a future release. + +### Customizing widgets' text input + +All the widgets that render a text input use the `BaseInputTemplate` component internally. If you need to customize all text inputs without customizing all widgets individually, you can provide a `BaseInputTemplate` component in the `templates` property of `Form` (see [Custom Templates](./custom-templates.md#baseinputtemplate)). + +### Wrapping an existing widget to customize it + +Sometimes you just need to customize the properties that are passed to an existing widget. +The way to do this varies based upon whether you are using core or some other theme (such as mui). + +Here is an example of modifying the `SelectWidget` to change the ordering of `enumOptions`: + +```tsx +import { WidgetProps } from '@rjsf/utils'; +import { getDefaultRegistry } from '@rjsf/core'; +import { Widgets } from '@rjsf/mui'; + +import myOptionsOrderFunction from './myOptionsOrderFunction'; + +const { + widgets: { SelectWidget }, +} = getDefaultRegistry(); // To get widgets from core +// const { SelectWidget } = Widgets; // To get widgets from a theme do this + +function MySelectWidget(props: WidgetProps) { + const { options } = props; + let { enumOptions } = options; + // Reorder the `enumOptions` however you want + enumOptions = myOptionsOrderFunction(enumOptions); + return ; +} +``` + +## Custom field components + +You can provide your own field components to a uiSchema for basically any json schema data type, by specifying a `ui:field` property. + +For example, let's create and register a dumb `geo` component handling a _latitude_ and a _longitude_: + +```tsx +import { RJSFSchema, UiSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + required: ['lat', 'lon'], + properties: { + lat: { type: 'number' }, + lon: { type: 'number' }, + }, +}; + +// Define a custom component for handling the root position object +class GeoPosition extends React.Component { + constructor(props: FieldProps) { + super(props); + this.state = { ...props.formData }; + } + + onChange(name) { + return (event) => { + this.setState( + { + [name]: parseFloat(event.target.value), + }, + () => this.props.onChange(this.state) + ); + }; + } + + render() { + const { lat, lon } = this.state; + return ( +
+ + +
+ ); + } +} + +// Define the custom field component to use for the root object +const uiSchema: UiSchema = { 'ui:field': 'geo' }; + +// Define the custom field components to register; here our "geo" +// custom field component +const fields: RegistryFieldsType = { geo: GeoPosition }; + +// Render the form with all the properties we just defined passed +// as props +render( + , + document.getElementById('app') +); +``` + +> Note: Registered fields can be reused across the entire schema. + +### Field props + +A field component will always be passed the following props: + +- `schema`: The JSON subschema object for this field; +- `uiSchema`: The [uiSchema](../api-reference/uiSchema.md) for this field; +- `idSchema`: The tree of unique ids for every child field; +- `formData`: The data for this field; +- `errorSchema`: The tree of errors for this field and its children; +- `registry`: A [registry](#the-registry-object) object (read next). +- `formContext`: A [formContext](../api-reference/form-props.md#formcontext) object (read next). +- `required`: The required status of this field; +- `disabled`: A boolean value stating if the field is disabled; +- `readonly`: A boolean value stating if the field is read-only; +- `autofocus`: A boolean value stating if the field should autofocus; +- `name`: The unique name of the field, usually derived from the name of the property in the JSONSchema +- `idPrefix`: To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids; Default is `root` +- `idSeparator`: To avoid using a path separator that is present in field names, it is possible to change the separator used for ids (Default is `_`) +- `rawErrors`: `An array of strings listing all generated error messages from encountered errors for this field +- `onChange`: The field change event handler; called with the updated form data and an optional `ErrorSchema` +- `onBlur`: The input blur event handler; call it with the field id and value; +- `onFocus`: The input focus event handler; call it with the field id and value; + +## The `registry` object + +The `registry` is an object containing the registered core, theme and custom fields and widgets as well as the root schema, form context, schema utils. + +- `fields`: The set of all fields used by the `Form`. Includes fields from `core`, theme-specific fields and any [custom registered fields](#custom-field-components); +- `widgets`: The set of all widgets used by the `Form`. Includes widgets from `core`, theme-specific widgets and any [custom registered widgets](#custom-component-registration), if any; +- `rootSchema`: The root schema, as passed to the `Form`, which can contain referenced [definitions](../json-schema/definitions.md); +- `formContext`: The [formContext](../api-reference/form-props.md#formcontext) that was passed to `Form`; +- `schemaUtils`: The current implementation of the `SchemaUtilsType` (from `@rjsf/utils`) in use by the `Form`. Used to call any of the validation-schema-based utility functions. + +The registry is passed down the component tree, so you can access it from your custom field, custom widget, custom template and `SchemaField` components. + +### Custom SchemaField + +**Warning:** This is a powerful feature as you can override the whole form behavior and easily mess it up. Handle with care. + +You can provide your own implementation of the `SchemaField` base React component for rendering any JSONSchema field type, including objects and arrays. This is useful when you want to augment a given field type with supplementary powers. + +To proceed so, pass a `fields` object having a `SchemaField` property to your `Form` component; here's an example: + +```tsx +import { RJSFSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const CustomSchemaField = function (props: FieldProps) { + return ( +
+

Yeah, I'm pretty dumb.

+
My props are: {JSON.stringify(props)}
+
+ ); +}; + +const fields: RegistryFieldsType = { + SchemaField: CustomSchemaField, +}; + +const schema: RJSFSchema = { + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +If you're curious how this could ever be useful, have a look at the [Kinto formbuilder](https://github.com/Kinto/formbuilder) repository to see how it's used to provide editing capabilities to any form field. + +Props passed to a custom SchemaField are the same as [the ones passed to a custom field](#field-props). + +### Custom ArraySchemaField + +Everything that was mentioned above for a `Custom SchemaField` applies, but this is only used to render the Array item `children` that are then passed to the `ArrayFieldItemTemplate`. +By default, `ArraySchemaField` is not actually implemented in the `fields` list since `ArrayField` falls back to `SchemaField` if `ArraySchemaField` is not provided. +If you want to customize how the individual items for an array are rendered, provide your implementation of `ArraySchemaField` as a `fields` override. + +```tsx +import { RJSFSchema, UiSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const CustomArraySchemaField = function (props: FieldProps) { + const { index, registry } = props; + const { SchemaField } = registry.fields; + const name = `Index ${index}`; + return ; +}; + +const fields: RegistryFieldsType = { + ArraySchemaField: CustomArraySchemaField, +}; + +const schema: RJSFSchema = { + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +### Custom Field by Id + +**Warning:** This is a powerful feature as you can override the whole form behavior and easily mess it up. Handle with care. + +You can provide your own implementation of the field component that applies to any schema or sub-schema based on the schema's `$id` value. This is useful when your custom field should be conditionally applied based on the schema rather than the property name or data type. + +To provide a custom field in this way, the `fields` prop should be an object which contains a key that matches the `$id` value of the schema which should have a custom field; here's an example: + +```tsx +import { RJSFSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const CustomIdField = function (props: FieldProps) { + return ( +
+

Yeah, I'm pretty dumb.

+
My props are: {JSON.stringify(props)}
+
+ ); +}; + +const fields: RegistryFieldsType = { + '/schemas/my-id': CustomIdField, +}; + +const schema: RJSFSchema = { + $id: '/schemas/my-id', + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +### Wrapping an existing field to customize it + +Sometimes you just need to customize the properties that are passed to an existing field. + +Here is an example of wrapping the `ObjectField` to tweak the `onChange` handler to look for a specific kind of bad data: + +```tsx +import { useCallback } from 'react'; +import { FieldProps } from '@rjsf/utils'; +import { getDefaultRegistry } from '@rjsf/core'; + +import checkBadData from './checkBadData'; + +const { + fields: { ObjectField }, +} = getDefaultRegistry(); + +function MyObjectField(props: FieldProps) { + const { onChange } = props; + const onChangeHandler = useCallback( + (newFormData: T | undefined, es?: ErrorSchema, id?: string) => { + let data = newFormData; + let error = es; + if (checkBadData(newFormData)) { + // Format the `error` and fix the `data` here + } + onChange(data, error, id); + }, + [onChange] + ); + return ; +} +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/advanced-customization/index.mdx b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/index.mdx new file mode 100644 index 0000000000..d645a03381 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/index.mdx @@ -0,0 +1,11 @@ +--- +title: Advanced Customization +description: Advanced customization documentation for react-jsonschema-form. + +--- + +import DocCardList from '@theme/DocCardList'; + +

{frontMatter.description}

+ + \ No newline at end of file diff --git a/packages/docs/versioned_docs/version-5.24.10/advanced-customization/internals.md b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/internals.md new file mode 100644 index 0000000000..1252f5b91e --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/internals.md @@ -0,0 +1,102 @@ +# Internals + +Miscellaneous internals of react-jsonschema-form are listed here. + +## JSON Schema supporting status + +This component follows [JSON Schema](http://json-schema.org/documentation.html) specs. We currently support JSON Schema-07 by default, but we also support other JSON schema versions through the [custom schema validation](../usage/validation.md#custom-meta-schema-validation) feature. Due to the limitation of form widgets, there are some exceptions as follows: + +- `additionalItems` keyword for arrays + + This keyword works when `items` is an array. `additionalItems: true` is not supported because there's no widget to represent an item of any type. In this case it will be treated as no additional items allowed. `additionalItems` being a valid schema is supported. + +- `anyOf`, `allOf`, and `oneOf`, or multiple `types` (i.e. `"type": ["string", "array"]`) + + The `anyOf` and `oneOf` keywords are supported; however, properties declared inside the `anyOf/oneOf` should not overlap with properties "outside" of the `anyOf/oneOf`. + + You can also use `oneOf` with [schema dependencies](../json-schema/dependencies.md#schema-dependencies) to dynamically add schema properties based on input data. + + The `allOf` keyword is supported; it uses [json-schema-merge-allof](https://github.com/mokkabonna/json-schema-merge-allof) to merge subschemas to render the final combined schema in the form. When these subschemas are incompatible, though (or if the library has an error merging it), the `allOf` keyword is dropped from the schema. + +- `"additionalProperties":false` produces incorrect schemas when used with [schema dependencies](../json-schema/dependencies.md#schema-dependencies). This library does not remove extra properties, which causes validation to fail. It is recommended to avoid setting `"additionalProperties":false` when you use schema dependencies. See [#848](https://github.com/rjsf-team/react-jsonschema-form/issues/848) [#902](https://github.com/rjsf-team/react-jsonschema-form/issues/902) [#992](https://github.com/rjsf-team/react-jsonschema-form/issues/992) + +## Handling of schema defaults + +This library automatically fills default values defined in the [JSON Schema](http://json-schema.org/documentation.html) as initial values in your form. This also works for complex structures in the schema. If a field has a default defined, it should always appear as default value in form. This also works when using [schema dependencies](../json-schema/dependencies.md#schema-dependencies). + +Since there is a complex interaction between any supplied original form data and any injected defaults, this library tries to do the injection in a way which keeps the original intention of the original form data. + +Check out the defaults example on the [live playground](https://rjsf-team.github.io/react-jsonschema-form/) to see this in action. + +### Merging of defaults into the form data + +There are three different cases which need to be considered for the merging. Objects, arrays and scalar values. This library always deeply merges any defaults with the existing form data for objects. + +This are the rules which are used when injecting the defaults: + +- When there is a scalar in the form data, nothing is changed. +- When the value is `undefined` in the form data, the default is created in the form data. +- When the value is an object in the form data, the defaults are deeply merged into the form data, using the rules defined here for the deep merge. +- Then the value is an array in the form data, defaults are only injected in existing array items. No new array items will be created, even if the schema has minItems or additional items defined. + +### Merging of defaults within the schema + +In the schema itself, defaults of parent elements are propagated into children. So when you have a schema which defines a deeply nested object as default, these defaults will be applied to children of the current node. This also merges objects defined at different levels together with the "deeper" not having precedence. If the parent node defines properties, which are not defined in the child, they will be merged so that the default for the child will be the merged defaults of parent and child. + +For arrays this is not the case. Defining an array, when a parent also defines an array, will be overwritten. This is only true when arrays are used in the same level, for objects within these arrays, they will be deeply merged again. + +## Custom array field buttons + +The `ArrayField` component provides a UI to add, copy, remove and reorder array items, and these buttons use [Bootstrap glyphicons](http://getbootstrap.com/components/#glyphicons). +If you don't use glyphicons but still want to provide your own icons or texts for these buttons, you can easily do so using CSS: + +> NOTE this only applies to the `@rjsf/core` theme + +```css +i.glyphicon { + display: none; +} +.btn-add::after { + content: 'Add'; +} +.array-item-copy::after { + content: 'Copy'; +} +.array-item-move-up::after { + content: 'Move Up'; +} +.array-item-move-down::after { + content: 'Move Down'; +} +.array-item-remove::after { + content: 'Remove'; +} +``` + +## Submit form programmatically + +You can use the reference to get your `Form` component and call the `submit` method to submit the form programmatically without a submit button. +This method will dispatch the `submit` event of the form, and the function, that is passed to `onSubmit` props, will be called. + +```tsx +import { createRef } from 'react'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import { Form } from '@rjsf/core'; +import validator from '@rjsf/validator-ajv8'; + +const onSubmit = ({ formData }) => console.log('Data submitted: ', formData); +let yourForm; + +const schema: RJSFSchema = { + type: 'string', +}; + +const formRef = createRef(); + +render( + , + document.getElementById('app') +); + +formRef.current.submit(); +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/advanced-customization/typescript.md b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/typescript.md new file mode 100644 index 0000000000..15205d017a --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/advanced-customization/typescript.md @@ -0,0 +1,279 @@ +# Typescript Support + +RJSF fully supports Typescript. +The [types and functions](../api-reference/utility-functions.md) exported by `@rjsf/utils` are fully typed (as needed) using one or more of the following 3 optional generics: + +- `T = any`: This represents the type of the `formData` and defaults to `any`. +- `S extends StrictRJSFSchema = RJSFSchema`: This represents the type of the `schema` and extends the `StrictRJSFSchema` type and defaults to the `RJSFSchema` type. +- `F extends FormContextType = any`: This represents the type of the `formContext`, extends the `FormContextType` type and defaults to `any`. + +Every other library in the `@rjsf/*` ecosystem use these same generics in their functions and React component definitions. +For instance, in the `@rjsf/core` library the definitions of the `Form` component and the `withTheme()` and `getDefaultRegistry()` functions are as follows: + +```ts +export default class Form< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any +> extends Component, FormState> { + // ... class implementation +} + +export default function withTheme( + themeProps: ThemeProps +) { + // ... function implementation +} + +export default function getDefaultRegistry< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any +>(): Omit, 'schemaUtils'> { + // ... function implementation +} +``` + +Out of the box, the defaults for these generics will work for all use-cases. +Providing custom types for any of these generics may be useful for situations where the caller is working with typed `formData`, `schema` or `formContext` props, Typescript is complaining and type casting isn't allowed. + +## Overriding generics + +### T + +The generic `T` is used to represent the type of the `formData` property passed into `Form`. +If you are working with a simple, unchanging JSON Schema and you have defined a type for the `formData` you are working with, you can override this generic as follows: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import { Form } from '@rjsf/core'; + +interface FormData { + foo?: string; + bar?: number; +} + +const schema: RJSFSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + bar: { type: 'number' }, + }, +}; + +const formData: FormData = {}; + +const validator = customizeValidator(); + +render( schema={schema} validator={validator} formData={formData} />, document.getElementById('app')); +``` + +### S + +The generic `S` is used to represent the type of the `schema` property passed into `Form`. +If you are using something like the [Ajv utility types for schemas](https://ajv.js.org/guide/typescript.html#utility-types-for-schemas) typing system, you can override this generic as follows: + +```tsx +import { JSONSchemaType } from 'ajv'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import { Form } from '@rjsf/core'; + +interface FormData { + foo?: string; + bar?: number; +} + +type MySchema = JSONSchemaType; + +const schema: MySchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + bar: { type: 'number' }, + }, +}; + +const validator = customizeValidator(); + +render( schema={schema} validator={validator} />, document.getElementById('app')); + +// Alternatively since you have the type, you could also use this +// const validator = customizeValidator(); +// render(( +// schema={schema} validator={validator} /> +//), document.getElementById("app")); +``` + +> NOTE: using this `Ajv typing system` has not been tested extensively with RJSF, so use carefully + +### F + +The generic `F` is used to represent the type of the `formContext` property passed into `Form`. +If you have a type for this data, you can override this generic as follows: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import { Form } from '@rjsf/core'; + +interface FormContext { + myCustomWidgetData: object; +} + +const schema: RJSFSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + bar: { type: 'number' }, + }, +}; + +const formContext: FormContext = { + myCustomWidgetData: { + enableCustomFeature: true, + }, +}; + +const validator = customizeValidator(); + +render( + schema={schema} validator={validator} formContext={formContext} />, + document.getElementById('app') +); +``` + +## Overriding generics in core + +As shown in previous examples, overriding the default `Form` from `@rjsf/core` is pretty straight forward. +Using the `withTheme()` function is just as easy: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import { withTheme, ThemeProps } from '@rjsf/core'; + +interface FormData { + foo?: string; + bar?: number; +} + +type MySchema = JSONSchemaType; + +const schema: MySchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + bar: { type: 'number' }, + }, +}; + +interface FormContext { + myCustomWidgetData: object; +} + +const theme: ThemeProps = { + widgets: { test: () =>
test
}, +}; + +const ThemedForm = withTheme(theme); + +const validator = customizeValidator(); + +const Demo = () => ; +``` + +## Overriding generics in other themes + +Since all the other themes in RJSF are extensions of `@rjsf/core`, overriding parts of these themes with custom generics is a little different. +The exported `Theme` and `Form` from any of the themes have been created using the generic defaults, and as a result, do not take generics themselves. +In order to override generics, special `generateForm()` and `generateTheme()` functions are exported for your use. + +### Overriding a Theme + +If you are doing something like the following to create a new theme based on `@rjsf/mui` to extend one or more `templates`: + +```tsx +import React from 'react'; +import { WidgetProps } from '@rjsf/utils'; +import { ThemeProps, withTheme } from '@rjsf/core'; +import validator from '@rjsf/validator-ajv8'; +import { Theme } from '@rjsf/mui'; + +const OldBaseInputTemplate = Theme.templates.BaseInputTemplate; + +// Force the underlying `TextField` component to always use size="small" +function MyBaseInputTemplate(props: WidgetProps) { + return ; +} + +const myTheme: ThemeProps = { + ...Theme, + templates: { + ...Theme.templates, + BaseInputTemplate: MyBaseInputTemplate, + }, +}; + +const ThemedForm = withTheme(myTheme); + +const Demo = () => ; +``` + +Then you would use the new `generateTheme()` and `generateForm()` functions as follows: + +```tsx +import React from 'react'; +import { WidgetProps } from '@rjsf/utils'; +import { ThemeProps, withTheme } from '@rjsf/core'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import { generateTheme } from '@rjsf/mui'; + +interface FormData { + foo?: string; + bar?: number; +} + +type MySchema = JSONSchemaType; + +const schema: MySchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + bar: { type: 'number' }, + }, +}; + +interface FormContext { + myCustomWidgetData: object; +} + +const Theme: ThemeProps = generateTheme(); + +const OldBaseInputTemplate = Theme.templates.BaseInputTemplate; + +// Force the underlying `TextField` component to always use size="small" +function MyBaseInputTemplate(props: WidgetProps) { + return ; +} + +const myTheme: ThemeProps = { + ...Theme, + templates: { + ...Theme.templates, + BaseInputTemplate: MyBaseInputTemplate, + }, +}; + +const ThemedForm = withTheme(myTheme); + +const validator = customizeValidator(); + +// You could also do since they are effectively the same: +// const ThemedForm = generateForm(myTheme); + +const Demo = () => ; +``` + +> NOTE: The same approach works for extending `widgets` and `fields` as well. diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/form-props.md b/packages/docs/versioned_docs/version-5.24.10/api-reference/form-props.md new file mode 100644 index 0000000000..8c14cd92ff --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/form-props.md @@ -0,0 +1,595 @@ +--- +title: Props +--- + +# <Form /> props + +## acceptcharset + +The value of this prop will be passed to the `accept-charset` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-accept-charset). + +## action + +The value of this prop will be passed to the `action` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-action). + +Note that 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`](#onSubmit) function, where you could send a request programmatically with `fetch` or similar. + +## autoComplete + +The value of this prop will be passed to the `autocomplete` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-autocomplete). + +## autocomplete + +Deprecated, same functionality as `autoComplete` + +## className + +The value of this prop will be passed to the `class` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form). + +## children + +You can provide custom buttons to your form via the `Form` component's `children`. If no children are provided, by default a `Submit` button will be rendered. + +For other ways to modify the default `Submit` button, see both the [Submit Button Options](./uiSchema.md#submitbuttonoptions) and the [SubmitButton Template](../advanced-customization/custom-templates.md#submitbutton) documentation. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +render( + +
+ + +
+ , + document.getElementById('app') +); +``` + +> **Warning:** There needs to be a button or an input with `type="submit"` to trigger the form submission (and then the form validation). + +## customValidate + +Formerly the `validate` prop. +The `customValidate` prop requires a function that specifies custom validation rules for the form. +See [Validation](../usage/validation.md) for more information. + +## experimental_defaultFormStateBehavior + +Experimental features to specify different form state behavior. +Currently, this only affects the handling of optional array fields where `minItems` is set and handling of setting defaults based on the value of `emptyObjectFields`. + +> **Warning:** This API is experimental and unstable, therefore breaking changes may be shipped in minor or patch releases. If you want to use this feature, we recommend pinning exact versions of `@rjsf/\*` packages in your package.json file or be ready to update your use of it when necessary. + +The following subsections represent the different keys in this object, with the tables explaining the values and their meanings. + +### `arrayMinItems` + +This optional subsection is an object with two optional fields, `populate` and `mergeExtraDefaults`. +When not specified, it defaults to `{ populate: 'all', mergeExtraDefaults: false }`. + +#### `arrayMinItems.populate` + +Optional enumerated flag controlling how array minItems are populated, defaulting to `all`: + +| Flag Value | Description | +| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `all` | Legacy behavior - populate minItems entries with default values initially and include empty array when no values have been defined. | +| `requiredOnly` | Ignore `minItems` on a field when calculating defaults unless the field is required. | +| `never` | Ignore `minItems` on a field when calculating defaults for required and non-required. Value will set only if defined `default` and from `formData` | + +#### `arrayMinItems.computeSkipPopulate` + +The signature and documentation for this property is as follow: + +##### computeSkipPopulate () + +A function that determines whether to skip populating the array with default values based on the provided validator, schema, and root schema. +If the function returns `true`, the array will not be populated with default values. +If the function returns `false`, the array will be populated with default values according to the `populate` option. + +###### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that is used to detect valid schema conditions +- schema: S - The schema for which resolving a condition is desired +- [rootSchema]: S - The root schema that will be forwarded to all the APIs + +###### Returns + +- boolean: A boolean indicating whether to skip populating the array with default values. + +##### Example + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + stringArray: { + type: 'array', + items: { type: 'string' }, + minItems: 1, + }, + numberArray: { + type: 'array', + items: { type: 'number' }, + minItems: 1, + }, + }, + required: ['stringArray', 'numberArray'], +}; + +const computeSkipPopulateNumberArrays = (validator, schema, rootSchema) => + // These conditions are needed to narrow down the type of the schema.items + !Array.isArray(schema?.items) && + typeof schema?.items !== 'boolean' && + schema?.items?.type === 'number', + +render( +
, + document.getElementById('app') +); +``` + +#### `arrayMinItems.mergeExtraDefaults` + +Optional boolean flag, defaulting to `false` when not specified. +When `formData` is provided and does not contain `minItems` worth of data, this flag controls whether the extra data provided by the defaults is appended onto the existing `formData` items to ensure the `minItems` condition is met. +When `false` (legacy behavior), only the `formData` provided is merged into the default form state, even if there are fewer than the `minItems`. +When `true`, the defaults are appended onto the end of the `formData` until the `minItems` condition is met. + +### `emptyObjectFields` + +Optional enumerated flag controlling how empty object fields are populated, defaulting to `populateAllDefaults`: + +| Flag Value | Description | +| -------------------------- | --------------------------------------------------------------------------------------------------------------------------- | +| `populateAllDefaults` | Legacy behavior - set default when there is a primitive value, an non-empty object field, or the field itself is required | +| `populateRequiredDefaults` | Only sets default when a value is an object and its parent field is required, or it is a primitive value and it is required | +| `skipDefaults` | Does not set defaults | +| `skipEmptyDefaults` | Does not set an empty default. It will still apply the default value if a default property is defined in your schema | + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { type: 'string' }, + minItems: 3, +}; + +render( + , + document.getElementById('app') +); +``` + +### `allOf` + +Optional enumerated flag controlling how empty defaults are populated when `allOf` schemas are provided, defaulting to `skipDefaults`: + +| Flag Value | Description | +| ------------------ | -------------------------------------------------------------------------------------------- | +| `skipDefaults` | Skip parsing defaults from `allOf` schemas | +| `populateDefaults` | Generate default values for properties in the `allOf` schema including `if-then-else` syntax | + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Example', + type: 'object', + properties: { + animalInfo: { + properties: { + animal: { + type: 'string', + default: 'Cat', + enum: ['Cat', 'Fish'], + }, + }, + allOf: [ + { + if: { + properties: { + animal: { + const: 'Cat', + }, + }, + }, + then: { + properties: { + food: { + type: 'string', + default: 'meat', + enum: ['meat', 'grass', 'fish'], + }, + }, + required: ['food'], + }, + }, + ], + }, + }, +}; + +render( + , + document.getElementById('app') +); +``` + +### constAsDefaults + +Optional enumerated flag controlling how const values are merged into the form data as defaults when dealing with undefined values, defaulting to `always`. +The defaulting behavior for this flag will always be controlled by the `emptyObjectField` flag value. +For instance, if `populateRequiredDefaults` is set and the const value is not required, it will not be set. + +| Flag Value | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `always` | A const value will always be merged into the form as a default. If there is are const values in a `oneOf` (for instance to create an enumeration with title different from the values), the first const value will be defaulted | +| `skipOneOf` | If const is in a `oneOf` it will NOT pick the first value as a default | +| `never` | A const value will never be used as a default | + +### mergeDefaultsIntoFormData + +Optional enumerated flag controlling how the defaults are merged into the form data when dealing with undefined values, defaulting to `useFormDataIfPresent`. + +NOTE: If there is a default for a field and the `formData` is unspecified, the default ALWAYS merges. + +| Flag Value | Description | +| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| `useFormDataIfPresent` | Legacy behavior - Do not merge defaults if there is a value for a field in `formData` even if that value is explicitly set to `undefined` | +| `useDefaultIfFormDataUndefined` | If the value of a field within the `formData` is `undefined`, then use the default value instead | + +## experimental_customMergeAllOf + +The `experimental_customMergeAllOf` function allows you to provide a custom implementation for merging `allOf` schemas. This can be particularly useful in scenarios where the default [json-schema-merge-allof](https://github.com/mokkabonna/json-schema-merge-allof) library becomes a performance bottleneck, especially with large and complex schemas or doesn't satisfy your needs. + +By providing your own implementation, you can potentially achieve significant performance improvements. For instance, if your use case only requires a subset of JSON Schema features, you can implement a faster, more tailored merging strategy. + +If you're looking for alternative `allOf` merging implementations, you might consider [allof-merge](https://github.com/udamir/allof-merge). + +**Warning:** This is an experimental feature. Only use this if you fully understand the implications of custom `allOf` merging and are prepared to handle potential edge cases. Incorrect implementations may lead to unexpected behavior or validation errors. + +```tsx +import { Form } from '@rjsf/core'; +import validator from '@rjsf/validator-ajv8'; + +const customMergeAllOf = (schema: RJSFSchema): RJSFSchema => { + // Your custom implementation here +}; + +render( + , + document.getElementById('app') +); +``` + +## disabled + +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. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +If you just want to disable some fields, see the `ui:disabled` parameter in `uiSchema`. + +## readonly + +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. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +If you just want to make some fields read-only, see the `ui:readonly` parameter in `uiSchema`. + +## enctype + +The value of this prop will be passed to the `enctype` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-enctype). + +## extraErrors + +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. +See [Validation](../usage/validation.md) for more information. + +## extraErrorsBlockSubmit + +If set to true, causes the `extraErrors` to become blocking when the form is submitted. + +## fields + +Dictionary of registered fields in the form. See [Custom Widgets and Fields](../advanced-customization/custom-widgets-fields.md) for more information. + +## focusOnFirstError + +If set to true, then the first field with an error will receive the focus when the form is submitted with errors. + +You can also provide a custom callback function to handle what happens when this function is called. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, RJSFValidationError } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +const focusOnError = (error: RJSFValidationError) => { + console.log('I need to handle focusing this error'); +}; + +render(, document.getElementById('app')); +``` + +## formContext + +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. + +See [AntD Customization](themes/antd/uiSchema.md#formcontext) for formContext customizations for the `antd` theme. +See [Semantic UI Customization](themes/semantic-ui/uiSchema.md#formcontext) for formContext customizations for the `semantic-ui` theme. + +## formData + +Often you'll want to prefill a form with existing data; this is done by passing a `formData` prop object matching the schema. + +## id + +The value of this prop will be passed to the `id` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form). + +## idPrefix + +To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids (the default is `root`). + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +This will render `` instead of `` + +## idSeparator + +To avoid using a path separator that is present in field names, it is possible to change the separator used for ids (the default is `_`). + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + first: { + type: 'string', + }, + }, +}; + +render(, document.getElementById('app')); +``` + +This will render `` instead of `` when rendering `first`. + +## liveOmit + +If `omitExtraData` and `liveOmit` are both set to true, then extra form data values that are not in any form field will be removed whenever `onChange` is called. Set to `false` by default. + +## liveValidate + +If set to true, the form will perform validation and show any validation errors whenever the form data is changed, rather than just on submit. + +## method + +The value of this prop will be passed to the `method` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-method). + +## name + +The value of this prop will be passed to the `name` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-name). + +## noHtml5Validate + +If set to true, turns off HTML5 validation on the form. Set to `false` by default. + +## noValidate + +If set to true, turns off all validation. Set to `false` by default. + +## omitExtraData + +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. + +## onBlur + +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. + +## onChange + +If you plan on being notified every time the form data are updated, you can pass an `onChange` handler, which will receive the same first argument as `onSubmit` any time a value is updated in the form. +It will also receive, as the second argument, the `id` of the field which experienced the change. +Generally, this will be the `id` of the field for which input data is modified. +In the case of adding/removing of new fields in arrays or objects with `additionalProperties` and the rearranging of items in arrays, the `id` will be that of the array or object itself, rather than the item/field being added, removed or moved. + +## onError + +To react when submitted form data are invalid, pass an `onError` handler. It will be passed the list of encountered errors: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; +const onError = (errors) => console.log('I have', errors.length, 'errors to fix'); + +render(, document.getElementById('app')); +``` + +## onFocus + +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. + +## onSubmit + +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: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; +const onSubmit = ({ formData }, e) => console.log('Data submitted: ', formData); + +render(, document.getElementById('app')); +``` + +> Note: If there are fields in the `formData` that are not represented in the schema, they will be retained by default. If you would like to remove those extra values on form submission, you may need to set the `omitExtraData` and/or `liveOmit` props. + +## schema + +**Required**! Form schema. We support JSON schema draft-07 by default. See [Schema Reference](https://json-schema.org/draft-07/json-schema-release-notes.html) for more information. + +## showErrorList + +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 at the `bottom` or `top` of the form. When set to false, only inline input validation errors will be shown. Set to `top` by default. See [Validation](../usage/validation.md) for more information. + +## tagName + +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. + +```tsx + +``` + +You can also provide a class/function component. + +```tsx +const CustomForm = props => +// ... + +``` + +## target + +The value of this prop will be passed to the `target` [HTML attribute on the form](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-target). + +## templates + +Dictionary of registered templates in the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. + +## transformErrors + +A function can be passed to this prop in order to make modifications to the default errors resulting from JSON Schema validation. See [Validation](../usage/validation.md) for more information. + +## translateString + +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. In addition to replaceable parameters, some of the strings support the use of markdown and simple html. + +One can use the [documentation](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/utils/src/enums.ts) of the `TranslatableString` enums to determine which enum values contain replaceable parameters and which support markdown and simple html. + +One could use this function to alter one or more of the existing english strings to better suit one's application or fully translate all strings into a different language. +Below is an example of changing a few of the english strings to something else: + +```ts +import { TranslatableString, englishStringTranslator, replaceStringParameters } from '@rjsf/utils'; + +function fixupSomeEnglishStrings(stringToTranslate: TranslatableString, params?: string[]): string { + switch (stringToTranslate) { + case TranslatableString.NewStringDefault: + return ''; // Use an empty string for the new additionalProperties string default value + case TranslatableString.KeyLabel: + return replaceStringParameters('%1 Key Name', params); // Add "Name" onto the end of the WrapIfAdditionalTemplate key label + default: + return englishStringTranslator(stringToTranslate, params); // Fallback to the default english + } +} +``` + +## uiSchema + +Form uiSchema. See [uiSchema Reference](uiSchema.md) for more information. + +## validator + +**Required**! An implementation of the `ValidatorType` interface that is needed for form validation to work. +`@rjsf/validator-ajv8` exports the implementation of this interface from RJSF version 4. + +## widgets + +Dictionary of registered widgets in the form. See [Custom Widgets and Fields](../advanced-customization/custom-widgets-fields.md) for more information. diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/index.mdx b/packages/docs/versioned_docs/version-5.24.10/api-reference/index.mdx new file mode 100644 index 0000000000..75c1ea28ff --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/index.mdx @@ -0,0 +1,10 @@ +--- +title: API Reference +description: API documentation for react-jsonschema-form. +--- + +import DocCardList from '@theme/DocCardList'; + +

{frontMatter.description}

+ + \ No newline at end of file diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/antd/uiSchema.md b/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/antd/uiSchema.md new file mode 100644 index 0000000000..1599a3474f --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/antd/uiSchema.md @@ -0,0 +1,46 @@ +# AntD Customization + +## formContext + +You can customize the look of the form by passing options to Ant-Design theme fields. + +The formContext antd object accepts `descriptionLocation`, `readonlyAsDisabled` properties. + +`descriptionLocation` can be `'below' | 'tooltip'`, the default is `'below'` which places the description below the form item. +You can set it to `tooltip` that put the description inside the tooltip. +Note that you should have antd 4.7+ to use `'tooltip'`. + +Setting `{readonlyAsDisabled: false}` on the formContext will make the antd theme treat readOnly fields as disabled. + +```tsx + +``` + +These are the `formContext` properties that you can modify to adjust the `antd` presentation: + +- `descriptionLocation`: Where to display the description, either 'below' or 'tooltip', defaults to 'below' +- `readonlyAsDisabled`: Whether to make the antd theme treat readOnly fields as disabled, defaults to true + +## Using Antd v5 theme + +You can use AntD v5 styling by wrapping your application with `StyleProvider` from `@ant-design/cssinjs`. + +By default, `@rjsf/antd` components are using the v4 styling. + +```tsx +import { StyleProvider } from '@ant-design/cssinjs'; + +const Component = () => { + return ( + + + + ); +}; +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/chakra-ui/uiSchema.md b/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/chakra-ui/uiSchema.md new file mode 100644 index 0000000000..3e4548b7e6 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/chakra-ui/uiSchema.md @@ -0,0 +1,31 @@ +# Chakra-UI Customization + +When using `@rjsf/chakra-ui` there are a couple of ways to customize the feel of the form. + +## Styling + +You can use `ChakraProvider`, where you can customize the field components at a theme level. +And, `uiSchema` allows for the use of a `"chakra"` `"ui:option"` to customize the styling of the form widgets. + +```json +{ + "yourField": { + "ui:options": { + "chakra": { + "p": "1rem", + "color": "blue.200", + "sx": { + "margin": "0 auto" + } + } + } + } +} +``` + +It accepts the theme accessible [style props](https://chakra-ui.com/docs/features/style-props) provided by [Chakra](https://chakra-ui.com/docs/getting-started) and [Emotion](https://emotion.sh/docs/introduction). + +### Limitations + +- The `chakra` option is only available for the Chakra-UI theme. +- The props are given to the parent component in the individual widget. To pass styles to the inner components, use the [`sx` prop](https://chakra-ui.com/docs/features/the-sx-prop). diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/semantic-ui/uiSchema.md b/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/semantic-ui/uiSchema.md new file mode 100644 index 0000000000..ee20f03a8c --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/themes/semantic-ui/uiSchema.md @@ -0,0 +1,119 @@ +# Semantic-UI Customization + +There are various options to pass to semantic theme fields. + +Note that every semantic property within uiSchema can be rendered in one of two ways: `{"ui:options": {semantic:{[property]: [value]}}}` + +In other words, the following uiSchema is equivalent: + +> Note: All fields have the following settings below as their default + +``` +fluid: Take on the size of its container. +inverted: Format to appear on dark backgrounds. +``` + +```json +{ + "ui:options": { + "semantic": { + "fluid": true, + "inverted": false, + "errorOptions": { + "size": "small", + "pointing": "above" + } + } + } +} +``` + +#### Semantic Widget Optional Properties + +- [Semantic props for TextWidget](https://react.semantic-ui.com/elements/input/) +- [Semantic props for CheckboxWidget](https://react.semantic-ui.com/modules/checkbox/) +- [Semantic props for SelectWidget](https://react.semantic-ui.com/modules/dropdown/) +- [Semantic props for RangeWidget](https://react.semantic-ui.com/elements/input/) +- [Semantic props for RadioWidget](https://react.semantic-ui.com/addons/radio/) +- [Semantic props for PasswordWidget](https://react.semantic-ui.com/elements/input/) +- [Semantic props for UpDownWidget](https://react.semantic-ui.com/elements/input/) +- [Semantic props for TextAreaWidget](https://react.semantic-ui.com/addons/text-area/) + +## errorOptions + +The uiSchema semantic object accepts an `errorOptions` property for each field of the schema: + +``` +size: determines the size of the error message dialog +pointing: determines the direction of the arrow on the error message dialog +``` + +Below are the current defaults + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:options': { + semantic: { + errorOptions: { + size: 'small', + pointing: 'above', + }, + }, + }, +}; +``` + +## semantic options uiSchema for array items + +To specify a uiSchema that applies to array items, specify the semantic uiSchema value within the `ui:options` property: + +``` +wrapItem: wrap each array item in a Segment +horizontalButtons: vertical buttons instead of the default horizontal +``` + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +const uiSchema: UiSchema = { + 'ui:options': { + semantic: { + wrapItem: true, + horizontalButtons: false, + }, + }, +}; + +render(, document.getElementById('app')); +``` + +## formContext + +The formContext semantic object accepts `wrapContent` ,`wrapLabel` properties. + +``` +wrapContent: wrap all inputs field content in a div, for custom styling +wrapLabel: wrap all labels in a div, for custom styling via CSS +``` + +```tsx + +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/uiSchema.md b/packages/docs/versioned_docs/version-5.24.10/api-reference/uiSchema.md new file mode 100644 index 0000000000..d4eaaaa208 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/uiSchema.md @@ -0,0 +1,566 @@ +# uiSchema + +JSON Schema is limited for describing how a given data type should be rendered as a form input component. That's why this library introduces the concept of uiSchema. + +A UI schema is basically an object literal providing information on **how** the form should be rendered, while the JSON schema tells **what**. + +The uiSchema object follows the tree structure of the form field hierarchy, and defines how each property should be rendered. + +Note that almost every property within uiSchema can be rendered in one of two ways: `{"ui:options": {[property]: [value]}}`, or `{"ui:[property]": value}`. + +In other words, the following `uiSchema`s are equivalent: + +```json +{ + "ui:title": "Title", + "ui:description": "Description", + "ui:classNames": "my-class", + "ui:submitButtonOptions": { + "props": { + "disabled": false, + "className": "btn btn-info" + }, + "norender": false, + "submitText": "Submit" + } +} +``` + +```json +{ + "ui:options": { + "title": "Title", + "description": "Description", + "classNames": "my-class", + "submitButtonOptions": { + "props": { + "disabled": false, + "className": "btn btn-info" + }, + "norender": false, + "submitText": "Submit" + } + } +} +``` + +For a full list of what is supported in the `uiSchema` see the `UiSchema` type in [@rjsf/utils/types.ts](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/utils/src/types.ts). +Be sure to pay attention to the hierarchical intersection to these other types: `UIOptionsBaseType` and `TemplatesType`. + +## Exceptions to the equivalence + +There are 4 properties that exist in a `UiSchema` that will not be found in an inner `ui:options` object. + +### ui:globalOptions + +The set of globally relevant `UiSchema` options that are read from the root-level `UiSchema` and stored in the `registry` for use everywhere. + +```ts +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:globalOptions': { copyable: true }, +}; +``` + +### ui:rootFieldId + +By default, this library will generate ids unique to the form for all rendered widgets. +If you plan on using multiple instances of the `Form` component in a same page, it's wise to declare a root prefix for these, using the `ui:rootFieldId` uiSchema directive: + +```ts +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:rootFieldId': 'myform', +}; +``` + +This will make all widgets have an id prefixed with `myform`. + +### ui:field + +The `ui:field` property overrides the `Field` implementation used for rendering any field in the form's hierarchy. +Specify either the name of a field that is used to look up an implementation from the `fields` list or an actual one-off `Field` component implementation itself. + +See [Custom Widgets and Fields](../advanced-customization/custom-widgets-fields.md#custom-field-components) for more information about how to use this property. + +### ui:fieldReplacesAnyOrOneOf + +By default, any field that is rendered for an `anyOf`/`oneOf` schema will be wrapped inside the `AnyOfField` or `OneOfField` component. +This default behavior may be undesirable if your custom field already handles behavior related to choosing one or more subschemas contained in the `anyOf`/`oneOf` schema. +By providing a `true` value for this flag in association with a custom `ui:field`, the wrapped components will be omitted, so just one instance of the custom field will be rendered. +If the flag is omitted or set to `false`, your custom field will be wrapped by `AnyOfField`/`OneOfField`. + +### ui:options + +The `ui:options` property cannot be nested inside itself and thus is the last exception. + +## ui:XXX or ui:options.XXX + +All the properties that follow can be specified in the `uiSchema` in either of the two equivalent ways. + +NOTE: The properties specific to array items can be found [here](../json-schema/arrays.md#array-item-uiSchema-options) + +### widget + +The `ui:widget` property overrides the `Widget` implementation used for rendering any field in the form's hierarchy. +Specify either the name of a widget that is used to look up an implementation from the `widgets` list or an actual one-off `Widget` component implementation itself. + +See [Custom Widgets and Fields](../advanced-customization/custom-widgets-fields.md) for more information about how to use this property. + +### classNames + +The uiSchema object accepts a `ui:classNames` property for each field of the schema: + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema = { + title: { + 'ui:classNames': 'task-title foo-bar', + }, +}; +``` + +Will result in: + +```html +
+ +
+``` + +### style + +The uiSchema object accepts a `ui:style` property for each field of the schema: + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema = { + title: { + 'ui:style': { color: 'red' }, + }, +}; +``` + +Will result in: + +```html +
+ +
+``` + +### autocomplete + +If you want to mark a text input, select or textarea input to use the HTML autocomplete feature, set the `ui:autocomplete` uiSchema directive to a valid [HTML autocomplete value](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values). + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:widget': 'textarea', + 'ui:autocomplete': 'on', +}; +``` + +### autofocus + +If you want to automatically focus on a text input or textarea input, set the `ui:autofocus` uiSchema directive to `true`. + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:widget': 'textarea', + 'ui:autofocus': true, +}; +``` + +### description + +Sometimes it's convenient to change the description of a field. This is the purpose of the `ui:description` uiSchema directive: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:widget': 'password', + 'ui:description': 'The best password', +}; +``` + +### disabled + +The `ui:disabled` uiSchema directive will disable all child widgets from a given field. + +> Note: If you're wondering about the difference between a `disabled` field and a `readonly` one: Marking a field as read-only will render it greyed out, but its text value will be selectable. Disabling it will prevent its value to be selected at all. + +### emptyValue + +The `ui:emptyValue` uiSchema directive provides the default value to use when an input for a field is empty + +### enumDisabled + +To disable an option, use the `enumDisabled` property in uiSchema. + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'string', + enum: ['one', 'two', 'three'], +}; + +const uiSchema: UiSchema = { + 'ui:enumDisabled': ['two'], +}; +``` + +### enumNames + +Allows a user to provide a list of labels for enum values in the schema. + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'number', + enum: [1, 2, 3], +}; +const uiSchema: UiSchema = { + 'ui:enumNames': ['one', 'two', 'three'], +}; +``` + +### filePreview + +The `FileWidget` can be configured to show a preview of an image or a download link for non-images using this flag. + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'string', + format: 'data-url', +}; +const uiSchema: UiSchema = { + 'ui:options': { + filePreview: true, + }, +}; +``` + +### help + +Sometimes it's convenient to add text next to a field to guide the end user filling it. This is the purpose of the `ui:help` uiSchema directive: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:widget': 'password', + 'ui:help': 'Hint: Make it strong!', +}; +``` + +![](https://i.imgur.com/scJUuZo.png) + +Help texts work for any kind of field at any level, and will always be rendered immediately below the field component widget(s) (after contextualized errors, if any). + +### hideError + +The `ui:hideError` uiSchema directive will, if set to `true`, hide the default error display for the given field AND all of its child fields in the hierarchy. + +If you need to enable the default error display of a child in the hierarchy after setting `hideError: true` on the parent field, simply set `hideError: false` on the child. + +This is useful when you have a custom field or widget that utilizes either the `rawErrors` or the `errorSchema` to manipulate and/or show the error(s) for the field/widget itself. + +### inputType + +To change the input type (for example, `tel` or `email`) you can specify the `inputType` in the `ui:options` uiSchema directive. + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:options': { + inputType: 'tel', + }, +}; +``` + +### label + +Field labels are rendered by default. +Labels may be omitted on a per-field by setting the `label` option to `false` in the `ui:options` uiSchema directive. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:options': { + label: false, + }, +}; + +render(, document.getElementById('app')); +``` + +They can also be omitted globally by setting the `label` option to `false` in the `ui:globalOptions` uiSchema directive. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:globalOptions': { + label: false, + }, +}; + +render(, document.getElementById('app')); +``` + +### order + +This property allows you to reorder the properties that are shown for a particular object. See [Objects](../json-schema/objects.md) for more information. + +### placeholder + +You can add placeholder text to an input by using the `ui:placeholder` uiSchema directive: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { type: 'string', format: 'uri' }; +const uiSchema: UiSchema = { + 'ui:placeholder': 'http://', +}; + +render(, document.getElementById('app')); +``` + +Fields using `enum` can also use `ui:placeholder`. The value will be used as the text for the empty option in the select widget. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { type: 'string', enum: ['First', 'Second'] }; +const uiSchema: UiSchema = { + 'ui:placeholder': 'Choose an option', +}; + +render(, document.getElementById('app')); +``` + +### readonly + +The `ui:readonly` uiSchema directive will mark all child widgets from a given field as read-only. This is equivalent to setting the `readOnly` property in the schema. + +> Note: If you're wondering about the difference between a `disabled` field and a `readonly` one: Marking a field as read-only will render it greyed out, but its text value will be selectable. Disabling it will prevent its value to be selected at all. + +### rows + +You can set the initial height of a textarea widget by specifying `rows` option. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:options': { + widget: 'textarea', + rows: 15, + }, +}; + +render(, document.getElementById('app')); +``` + +### title + +Sometimes it's convenient to change a field's title. This is the purpose of the `ui:title` uiSchema directive: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { type: 'string' }; +const uiSchema: UiSchema = { + 'ui:widget': 'password', + 'ui:title': 'Your password', +}; +``` + +### submitButtonOptions + +Sometimes it's convenient to change the behavior of the submit button for the form. This is the purpose of the `ui:submitButtonOptions` uiSchema directive: + +You can pass any other prop to the submit button if you want, by default, this library will set the following options / props mentioned below for all submit buttons: + +#### `norender` option + +You can set this property to `true` to remove the submit button completely from the form. Nice option, if the form is just for viewing purposes. + +#### `submitText` option + +You can use this option to change the text of the submit button. Set to "Submit" by default. + +#### `props` section + +You can pass any other prop to the submit button if you want, via this section. + +##### `disabled` prop + +You can use this option to disable the submit button. + +##### `className` prop + +You can use this option to specify a class name for the submit button. + +```tsx +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:submitButtonOptions': { + props: { + disabled: false, + className: 'btn btn-info', + }, + norender: false, + submitText: 'Submit', + }, +}; +``` + +## `duplicateKeySuffixSeparator` option + +When using `additionalProperties`, key collision is prevented by appending a unique integer suffix to the duplicate key. +For example, when you add a key named `myKey` to a form where `myKey` is already defined, then your new key will become `myKey-1`. +You can use `ui:duplicateKeySuffixSeparator` to override the default separator, `"-"` with a string of your choice on a per-field basis. + +You can also set this in the `ui:globalOptions` to have the same separator used everywhere. + +```ts +import { UiSchema } from '@rjsf/utils'; + +const uiSchema = { + 'ui:globalOptions': { + duplicateKeySuffixSeparator: '_', + }, +}; +``` + +## Using uiSchema with oneOf, anyOf + +### anyOf + +The uiSchema will work with elements inside an `anyOf` as long as the uiSchema defines the `anyOf` key at the same level as the `anyOf` within the `schema`. +Because the `anyOf` in the `schema` is an array, so must be the one in the `uiSchema`. +If you want to override the titles of the first two elements within the `anyOf` list you would do the following: + +```ts +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'object', + anyOf: [ + { + title: 'Strings', + type: 'string', + }, + { + title: 'Numbers', + type: 'number', + }, + { + title: 'Booleans', + type: 'boolean', + }, + ], +}; + +const uiSchema: UiSchema = { + anyOf: [ + { + 'ui:title': 'Custom String Title', + }, + { + 'ui:title': 'Custom Number Title', + }, + ], +}; +``` + +> NOTE: Because the third element in the `schema` does not have an associated element in the `uiSchema`, it will keep its original title. + +### oneOf + +The uiSchema will work with elements inside an `oneOf` as long as the uiSchema defines the `oneOf` key at the same level as the `oneOf` within the `schema`. +Because the `oneOf` in the `schema` is an array, so must be the one in the `uiSchema`. +If you want to override the titles of the first two elements within the `oneOf` list you would do the following: + +```ts +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'object', + oneOf: [ + { + title: 'Strings', + type: 'string', + }, + { + title: 'Numbers', + type: 'number', + }, + { + title: 'Booleans', + type: 'boolean', + }, + ], +}; + +const uiSchema: UiSchema = { + oneOf: [ + { + 'ui:title': 'Custom String Title', + }, + { + 'ui:title': 'Custom Number Title', + }, + ], +}; +``` + +> NOTE: Because the third element in the `schema` does not have an associated element in the `uiSchema`, it will keep its original title. + +## Theme Options + +- [AntD Customization](themes/antd/uiSchema.md) +- [Chakra-UI Customization](themes/chakra-ui/uiSchema.md) +- [Semantic-UI Customization](themes/semantic-ui/uiSchema.md) diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/utility-functions.md b/packages/docs/versioned_docs/version-5.24.10/api-reference/utility-functions.md new file mode 100644 index 0000000000..ef89d9e521 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/utility-functions.md @@ -0,0 +1,1242 @@ +# RJSF utility functions, constants and types + +In version 5, the utility functions from `@rjsf/core/utils` were refactored into their own library called `@rjsf/utils`. +These utility functions are separated into two distinct groups. +The first, larger, group are the [functions](#non-validator-utility-functions) that do NOT require a `ValidatorType` interface be provided as one of their parameters. +The second, smaller, group are the [functions](#validator-based-utility-functions) that DO require a `ValidatorType` interface be provided as a parameter. +There is also a helper [function](#schema-utils-creation-function) used to create a `SchemaUtilsType` implementation from a `ValidatorType` implementation and `rootSchema` object. + +## Constants + +The `@rjsf/utils` package exports a set of constants that represent all the keys into various elements of a RJSFSchema or UiSchema that are used by the various utility functions. +In addition to those keys, there is the special `ADDITIONAL_PROPERTY_FLAG` flag that is added to a schema under certain conditions by the `retrieveSchema()` utility. + +These constants can be found on GitHub [here](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/utils/src/constants.ts). + +## Types + +Additionally, the Typescript types used by the utility functions represent nearly all the types used by RJSF. +Those types are exported for use by `@rjsf/core` and all the themes, as well as any customizations you may build. + +These types can be found on GitHub [here](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/utils/src/types.ts). + +## Enums + +There are enumerations in `@rjsf/utils` that are exported for use by `@rjsf/core` and all the themes, as well as any customizations you may build. + +These enums can be found on GitHub [here](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/utils/src/enums.ts). + +## Non-Validator utility functions + +### allowAdditionalItems() + +Checks the schema to see if it is allowing additional items, by verifying that `schema.additionalItems` is an object. +The user is warned in the console if `schema.additionalItems` has the value `true`. + +#### Parameters + +- schema: S - The schema object to check + +#### Returns + +- boolean: True if additional items is allowed, otherwise false + +### ariaDescribedByIds() + +Return a list of element ids that contain additional information about the field that can be used to as the aria description of the field. + +#### Parameters + +- id: IdSchema<T> | string - Either simple string id or an IdSchema from which to extract it +- [includeExamples=false]: boolean - Optional flag, if true, will add the `examplesId` into the list + +#### Returns + +- string: The string containing the list of ids for use in an `aria-describedBy` attribute + +### asNumber() + +Attempts to convert the string into a number. If an empty string is provided, then `undefined` is returned. +If a `null` is provided, it is returned. +If the string ends in a `.` then the string is returned because the user may be in the middle of typing a float number. +If a number ends in a pattern like `.0`, `.20`, `.030`, string is returned because the user may be typing number that will end in a non-zero digit. +Otherwise, the string is wrapped by `Number()` and if that result is not `NaN`, that number will be returned, otherwise the string `value` will be. + +#### Parameters + +- value: string | null - The string or null value to convert to a number + +#### Returns + +- undefined | null | string | number: The `value` converted to a number when appropriate, otherwise the `value` + +### canExpand() + +Checks whether the field described by `schema`, having the `uiSchema` and `formData` supports expanding. +The UI for the field can expand if it has additional properties, is not forced as non-expandable by the `uiSchema` and the `formData` object doesn't already have `schema.maxProperties` elements. + +#### Parameters + +- schema: S - The schema for the field that is being checked +- [uiSchema={}]: UiSchema - The uiSchema for the field +- [formData]: T | undefined - The formData for the field + +#### Returns + +- boolean: True if the schema element has additionalProperties, is expandable, and not at the maxProperties limit + +### createErrorHandler() + +Given a `formData` object, recursively creates a `FormValidation` error handling structure around it + +#### Parameters + +- formData: T - The form data around which the error handler is created + +#### Returns + +- FormValidation<T>: A `FormValidation` object based on the `formData` structure + +### dataURItoBlob() + +Given the `FileReader.readAsDataURL()` based `dataURI` extracts that data into an actual Blob along with the name +of that Blob if provided in the URL. If no name is provided, then the name falls back to `unknown`. + +#### Parameters + +- dataURI: string - The `DataUrl` potentially containing name and raw data to be converted to a Blob + +#### Returns + +- { blob: Blob, name: string }: An object containing a Blob and its name, extracted from the URI + +### dateRangeOptions<S extends StrictRJSFSchema = RJSFSchema>() + +Returns a list of options for a date range between `start` and `stop`. +If the start date is greater than the end date, then the date range is reversed. +If `start` and `stop` are negative numbers (or zero), then they will be treated as relative to the current year. + +#### Parameters + +- start: number - The starting point of the date range +- stop: number - The ending point of the date range + +#### Returns + +- EnumOptionsType<S>[]: The list of EnumOptionsType for the date range between `start` and `stop` + +#### Throws + +- Error when `start` and `stop` aren't both <= 0 or > 0 + +### deepEquals() + +Implements a deep equals using the `lodash.isEqualWith` function, that provides a customized comparator that assumes all functions are equivalent. + +#### Parameters + +- a: any - The first element to compare +- b: any - The second element to compare + +#### Returns + +- boolean: True if the `a` and `b` are deeply equal, false otherwise + +### descriptionId() + +Return a consistent `id` for the field description element. + +#### Parameters + +- id: IdSchema<T> | string - Either simple string id or an IdSchema from which to extract it + +#### Returns + +- string: The consistent id for the field description element from the given `id` + +### englishStringTranslator() + +Translates a `TranslatableString` value `stringToTranslate` into english. +When a `params` array is provided, each value in the array is used to replace any of the replaceable parameters in the `stringToTranslate` using the `%1`, `%2`, etc. replacement specifiers. + +#### Parameters + +stringToTranslate: TranslatableString - The `TranslatableString` value to convert to english +[params]: string[] - The optional list of replaceable parameter values to substitute to the english string + +#### Returns + +- string: The `stringToTranslate` itself with any replaceable parameter values substituted + +### enumOptionsDeselectValue<S extends StrictRJSFSchema = RJSFSchema>() + +Removes the enum option value at the `valueIndex` from the currently `selected` (list of) value(s). +If `selected` is a list, then that list is updated to remove the enum option value with the `valueIndex` in `allEnumOptions`. +If it is a single value, then if the enum option value with the `valueIndex` in `allEnumOptions` matches `selected`, undefined is returned, otherwise the `selected` value is returned. + +#### Parameters + +- valueIndex: string | number - The index of the value to be removed from the selected list or single value +- [selected]: EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] | undefined - The current (list of) selected value(s) +- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions + +#### Returns + +- EnumOptionsType<S>["value"][]: The updated `selected` list with the `value` removed from it + +### enumOptionsIndexForValue<S extends StrictRJSFSchema = RJSFSchema>() + +Returns the index(es) of the options in `allEnumOptions` whose value(s) match the ones in `value`. +All the `enumOptions` are filtered based on whether they are a "selected" `value` and the index of each selected one is then stored in an array. +If `multiple` is true, that array is returned, otherwise the first element in the array is returned. + +#### Parameters + +- value: EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] - The single value or list of values for which indexes are desired +- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions +- [multiple=false]: boolean - Optional flag, if true will return a list of index, otherwise a single one + +#### Returns + +- string | string[] | undefined: A single string index for the first `value` in `allEnumOptions`, if not `multiple`. Otherwise, the list of indexes for (each of) the value(s) in `value`. + +### enumOptionsIsSelected<S extends StrictRJSFSchema = RJSFSchema>() + +Determines whether the given `value` is (one of) the `selected` value(s). + +#### Parameters + +- value: EnumOptionsType<S>["value"] - The value being checked to see if it is selected +- selected: EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] - The current selected value or list of values +- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions + +#### Returns + +- boolean: true if the `value` is one of the `selected` ones, false otherwise + +### enumOptionsSelectValue<S extends StrictRJSFSchema = RJSFSchema>() + +Add the `value` to the list of `selected` values in the proper order as defined by `allEnumOptions`. + +#### Parameters + +- valueIndex: string | number - The index of the value that should be selected +- selected: EnumOptionsType<S>["value"][] - The current list of selected values +- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions + +#### Returns + +- EnumOptionsType<S>["value"][]: The updated list of selected enum values with `value` added to it in the proper location + +### enumOptionsValueForIndex<S extends StrictRJSFSchema = RJSFSchema>() + +Returns the value(s) from `allEnumOptions` at the index(es) provided by `valueIndex`. +If `valueIndex` is not an array AND the index is not valid for `allEnumOptions`, `emptyValue` is returned. +If `valueIndex` is an array, AND it contains an invalid index, the returned array will have the resulting undefined values filtered out, leaving only valid values or in the worst case, an empty array. + +#### Parameters + +- valueIndex: string | number | Array - The index(es) of the value(s) that should be returned +- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions +- [emptyValue]: EnumOptionsType<S>["value"] | undefined - The value to return when the non-array `valueIndex` does not refer to a real option + +#### Returns + +- EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] | undefined: The single or list of values specified by the single or list of indexes if they are valid. Otherwise, `emptyValue` or an empty list. + +### errorId() + +Return a consistent `id` for the field error element. + +#### Parameters + +- id: IdSchema<T> | string - Either simple string id or an IdSchema from which to extract it + +#### Returns + +- string: The consistent id for the field error element from the given `id` + +### examplesId() + +Return a consistent `id` for the field examples element. + +#### Parameters + +- id: IdSchema<T> | string - Either simple string id or an IdSchema from which to extract it + +#### Returns + +- string: The consistent id for the field examples element from the given `id` + +### findSchemaDefinition<S extends StrictRJSFSchema = RJSFSchema>() + +Given the name of a `$ref` from within a schema, using the `rootSchema`, look up and return the sub-schema using the path provided by that reference. +If `#` is not the first character of the reference, or the path does not exist in the schema, then throw an Error. +Otherwise, return the sub-schema. Also deals with nested `$ref`s in the sub-schema. + +#### Parameters + +- $ref: string - The ref string for which the schema definition is desired +- [rootSchema={}]: S - The root schema in which to search for the definition + +#### Returns + +- S: The sub-schema within the `rootSchema` which matches the `$ref` if it exists + +#### Throws + +- Error indicating that no schema for that reference exists + +### getChangedFields(a: unknown, b: unknown) + +Compares two objects and returns the names of the fields that have changed. +This function iterates over each field of object `a`, using `_.isEqual` to compare the field value with the corresponding field value in object `b`. +If the values are different, the field name will be included in the returned array. + +#### Parameters + +- a: unknown - The first object, representing the original data to compare. +- b: unknown - The second object, representing the updated data to compare. + +#### Returns + +- string[] : An array of field names that have changed. + +#### Example + +```typescript +const a = { name: 'John', age: 30 }; +const b = { name: 'John', age: 31 }; +const changedFields = getChangedFields(a, b); +console.log(changedFields); // Output: ['age'] +``` + +### getDiscriminatorFieldFromSchema<S extends StrictRJSFSchema = RJSFSchema>() + +Returns the `discriminator.propertyName` when defined in the `schema` if it is a string. A warning is generated when it is not a string. +Returns `undefined` when a valid discriminator is not present. + +#### Parameters + +- schema: S - The schema from which the discriminator is potentially obtained + +#### Returns + +- string | undefined: The `discriminator.propertyName` if it exists in the schema, otherwise `undefined` + +### getDateElementProps() + +Given date & time information with optional yearRange & format, returns props for DateElement + +#### Parameters + +- date: DateObject - Object containing date with optional time information +- time: boolean - Determines whether to include time or not +- [yearRange=[1900, new Date().getFullYear() + 2]]: [number, number] - Controls the list of years to be displayed +- [format='YMD']: DateElementFormat - Controls the order in which day, month and year input element will be displayed + +#### Returns + +- Array of props for DateElement + +### getInputProps() + +Using the `schema`, `defaultType` and `options`, extract out the props for the `` element that make sense. + +#### Parameters + +- schema: S - The schema for the field provided by the widget +- [defaultType]: string | undefined - The default type, if any, for the field provided by the widget +- [options={}]: UIOptionsType - The UI Options for the field provided by the widget +- [autoDefaultStepAny=true]: boolean - Determines whether to auto-default step=any when the type is number and no step + +#### Returns + +- InputPropsType: The extracted `InputPropsType` object + +### getOptionMatchingSimpleDiscriminator() + +Compares the value of `discriminatorField` within `formData` against the value of `discriminatorField` within schema for each `option`. Returns index of first `option` whose discriminator matches formData. Returns `undefined` if there is no match. + +This function does not work with discriminators of `"type": "object"` and `"type": "array"` + +#### Parameters + +- [formData]: T | undefined - The current formData, if any, used to figure out a match +- options: S[] - The list of options to find a matching options from +- [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected + +#### Returns + +- number | undefined: index of the matched option + +### getSchemaType() + +Gets the type of a given `schema`. +If the type is not explicitly defined, then an attempt is made to infer it from other elements of the schema as follows: + +- schema.const: Returns the `guessType()` of that value +- schema.enum: Returns `string` +- schema.properties: Returns `object` +- schema.additionalProperties: Returns `object` +- type is an array with a length of 2 and one type is 'null': Returns the other type + +#### Parameters + +- schema: S - The schema for which to get the type + +#### Returns + +- string | string[] | undefined: The type of the schema + +### getSubmitButtonOptions() + +Extracts any `ui:submitButtonOptions` from the `uiSchema` and merges them onto the `DEFAULT_OPTIONS` + +#### Parameters + +- [uiSchema={}]: UiSchema - the UI Schema from which to extract submit button props + +#### Returns + +- UISchemaSubmitButtonOptions: The merging of the `DEFAULT_OPTIONS` with any custom ones + +### getUiOptions() + +Get all passed options from ui:options, and ui:<optionName>, returning them in an object with the `ui:` stripped off. +Any `globalOptions` will always be returned, unless they are overridden by options in the `uiSchema`. + +#### Parameters + +- [uiSchema={}]: UiSchema - The UI Schema from which to get any `ui:xxx` options +- [globalOptions={}]: GlobalUISchemaOptions - The optional Global UI Schema from which to get any fallback `xxx` options + +#### Returns + +- UIOptionsType An object containing all of the `ui:xxx` options with the `ui:` stripped off along with all `globalOptions` + +### getTemplate, T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>() + +Returns the template with the given `name` from either the `uiSchema` if it is defined or from the `registry` +otherwise. NOTE, since `ButtonTemplates` are not overridden in `uiSchema` only those in the `registry` are returned. + +#### Parameters + +- name: Name - The name of the template to fetch, restricted to the keys of `TemplatesType` +- registry: Registry - The `Registry` from which to read the template +- [uiOptions={}]: UIOptionsType - The `UIOptionsType` from which to read an alternate template + +#### Returns + +- TemplatesType[Name] - The template from either the `uiSchema` or `registry` for the `name` + +### getWidget() + +Given a schema representing a field to render and either the name or actual `Widget` implementation, returns the +React component that is used to render the widget. If the `widget` is already a React component, then it is wrapped +with a `MergedWidget`. Otherwise an attempt is made to look up the widget inside of the `registeredWidgets` map based +on the schema type and `widget` name. If no widget component can be found an `Error` is thrown. + +#### Parameters + +- schema: S - The schema for the field +- widget: Widget | string - Either the name of the widget OR a `Widget` implementation to use +- [registeredWidgets={}]: RegistryWidgetsType - A registry of widget name to `Widget` implementation + +#### Returns + +- Widget: The `Widget` component to use + +#### Throws + +- An error if there is no `Widget` component that can be returned + +### guessType() + +Given a specific `value` attempts to guess the type of a schema element. In the case where we have to implicitly +create a schema, it is useful to know what type to use based on the data we are defining. + +#### Parameters + +- value: any - The value from which to guess the type + +#### Returns + +- string: The best guess for the object type + +### hashForSchema<S extends StrictRJSFSchema = RJSFSchema>() + +Stringifies the schema and returns the hash of the resulting string. + +#### Parameters + +- schema: S - The schema for which the hash is desired + +#### Returns + +- string: The string obtained from the hash of the stringified schema + +### hasWidget() + +Detects whether the `widget` exists for the `schema` with the associated `registryWidgets` and returns true if it does, or false if it doesn't. + +#### Parameters + +- schema: S - The schema for the field +- widget: Widget | string - Either the name of the widget OR a `Widget` implementation to use +- [registeredWidgets={}]: RegistryWidgetsType - A registry of widget name to `Widget` implementation + +#### Returns + +- boolean: True if the widget exists, false otherwise + +### helpId() + +Return a consistent `id` for the field help element. + +#### Parameters + +- id: IdSchema<T> | string - Either simple string id or an IdSchema from which to extract it + +#### Returns + +- string: The consistent id for the field help element from the given `id` + +### isConstant<S extends StrictRJSFSchema = RJSFSchema>() + +This function checks if the given `schema` matches a single constant value. +This happens when either the schema has an `enum` array with a single value or there is a `const` defined. + +#### Parameters + +- schema: S - The schema for a field + +#### Returns + +- boolean: True if the `schema` has a single constant value, false otherwise + +### isCustomWidget() + +Checks to see if the `uiSchema` contains the `widget` field and that the widget is not `hidden` + +#### Parameters + +- uiSchema: UiSchema - The UI Schema from which to detect if it is customized + +#### Returns + +- boolean: True if the `uiSchema` describes a custom widget, false otherwise + +### isFixedItems<S extends StrictRJSFSchema = RJSFSchema>() + +Detects whether the given `schema` contains fixed items. +This is the case when `schema.items` is a non-empty array that only contains objects. + +#### Parameters + +- schema: S - The schema in which to check for fixed items + +#### Returns + +- boolean: True if there are fixed items in the schema, false otherwise + +### isObject() + +Determines whether a `thing` is an object for the purposes of RSJF. +In this case, `thing` is an object if it has the type `object` but is NOT null, an array or a File. + +#### Parameters + +- thing: any - The thing to check to see whether it is an object + +#### Returns + +- boolean: True if it is a non-null, non-array, non-File object + +### labelValue() + +Helper function that will return the value to use for a widget `label` based on `hideLabel`. +The `fallback` is used as the return value from the function when `hideLabel` is true. +Due to the implementation of theme components, it may be necessary to return something other than `undefined` to cause the theme component to not render a label. +Some themes require may `false` and others may require an empty string. + +#### Parameters + +- [label]: string | ReactElement | undefined - The label string or component to render when not hidden +- [hideLabel]: boolean| undefined - Flag, if true, will cause the label to be hidden +- [fallback]: undefined | false | '' - One of 3 values, `undefined` (the default), `false` or an empty string + +- #### Returns + +- string | boolean | undefined: `fallback` if `hideLabel` is true, otherwise `label` + +### localToUTC() + +Converts a local Date string into a UTC date string + +#### Parameters + +- dateString: string - The string representation of a date as accepted by the `Date()` constructor + +#### Returns + +- string | undefined: A UTC date string if `dateString` is truthy, otherwise undefined + +### mergeDefaultsWithFormData() + +Merges the `defaults` object of type `T` into the `formData` of type `T` + +When merging defaults and form data, we want to merge in this specific way: + +- objects are deeply merged +- arrays are merged in such a way that: + - when the array is set in form data, only array entries set in form data are deeply merged; additional entries from the defaults are ignored unless `mergeExtraArrayDefaults` is true, in which case the extras are appended onto the end of the form data + - when the array is not set in form data, the default is copied over +- scalars are overwritten/set by form data + +#### Parameters + +- [defaults]: T | undefined - The defaults to merge +- [formData]: T | undefined - The form data into which the defaults will be merged +- [mergeExtraArrayDefaults=false]: boolean - If true, any additional default array entries are appended onto the formData +- [defaultSupercedesUndefined=false]: boolean - If true, an explicit undefined value will be overwritten by the default value + +#### Returns + +- T | undefined: The resulting merged form data with defaults + +### mergeObjects() + +Recursively merge deeply nested objects. + +#### Parameters + +- obj1: GenericObjectType - The first object to merge +- obj2: GenericObjectType - The second object to merge +- [concatArrays=false]: boolean | "preventDuplicates" - Optional flag that, when true, will cause arrays to be concatenated. Use "preventDuplicates" to merge arrays in a manner that prevents any duplicate entries from being merged. + +#### Returns + +@returns - A new object that is the merge of the two given objects + +### mergeSchemas() + +Recursively merge deeply nested schemas. +The difference between mergeSchemas and mergeObjects is that mergeSchemas only concats arrays for values under the 'required' keyword, and when it does, it doesn't include duplicate values. NOTE: Uses shallow comparison for the duplicate checking. + +#### Parameters + +- obj1: GenericObjectType - The first object to merge +- obj2: GenericObjectType - The second object to merge + +#### Returns + +- GenericObjectType: The merged schema object + +### optionId() + +Return a consistent `id` for the `optionIndex`s of a `Radio` or `Checkboxes` widget + +#### Parameters + +- id: string - The id of the parent component for the option +- optionIndex: number - The index of the option for which the id is desired + +#### Returns + +- string: An id for the option index based on the parent `id` + +### optionsList<S extends StrictRJSFSchema = RJSFSchema, T = any, F extends FormContextType = any>() + +Gets the list of options from the `schema`. If the schema has an enum list, then those enum values are returned. +The labels for the options will be extracted from the non-standard, RJSF-deprecated `enumNames` if it exists, otherwise +the label will be the same as the `value`. If the schema has a `oneOf` or `anyOf`, then the value is the list of +`const` values from the schema and the label is either the `schema.title` or the value. If a `uiSchema` is provided +and it has the `ui:enumNames` matched with `enum` or it has an associated `oneOf` or `anyOf` with a list of objects +containing `ui:title` then the UI schema values will replace the values from the schema. + +NOTE: `enumNames` is deprecated and will be removed in a future major version of RJSF. Use the "ui:enumNames" property in the uiSchema instead. + +#### Parameters + +- schema: S - The schema from which to extract the options list +- uiSchema: UiSchema - The optional uiSchema from which to get alternate labels for the options + +#### Returns + +- { schema?: S, label: string, value: any }: The list of options from the schema + +### orderProperties() + +Given a list of `properties` and an `order` list, returns a list that contains the `properties` ordered correctly. +If `order` is not an array, then the untouched `properties` list is returned. +Otherwise `properties` is ordered per the `order` list. +If `order` contains a '_' then any `properties` that are not mentioned explicity in `order` will be places in the location of the `_`. + +#### Parameters + +- properties: string[] - The list of property keys to be ordered +- order: string[] - An array of property keys to be ordered first, with an optional '\*' property + +#### Returns + +- string[]: A list with the `properties` ordered + +#### Throws + +- Error when the properties cannot be ordered correctly + +### pad() + +Returns a string representation of the `num` that is padded with leading "0"s if necessary + +#### Parameters + +- num: number - The number to pad +- width: number - The width of the string at which no lead padding is necessary + +#### Returns + +- string: The number converted to a string with leading zero padding if the number of digits is less than `width` + +### parseDateString() + +Parses the `dateString` into a `DateObject`, including the time information when `includeTime` is true + +#### Parameters + +- dateString: string - The date string to parse into a DateObject +- [includeTime=true]: boolean - Optional flag, if false, will not include the time data into the object + +#### Returns + +- DateObject: The date string converted to a `DateObject` + +#### Throws + +- Error when the date cannot be parsed from the string + +### rangeSpec<S extends StrictRJSFSchema = RJSFSchema>() + +Extracts the range spec information `{ step?: number, min?: number, max?: number }` that can be spread onto an HTML input from the range analog in the schema `{ multipleOf?: number, minimum?: number, maximum?: number }`. + +#### Parameters + +- schema: S - The schema from which to extract the range spec + +#### Returns + +- RangeSpecType: A range specification from the schema + +### replaceStringParameters() + +Potentially substitutes all replaceable parameters with the associated value(s) from the `params` if available. +When a `params` array is provided, each value in the array is used to replace any of the replaceable parameters in the `inputString` using the `%1`, `%2`, etc. replacement specifiers. + +#### Parameters + +- inputString: string - The string which will be potentially updated with replacement parameters +- [params]: string[] - The optional list of replaceable parameter values to substitute into the english string + +#### Returns + +- string: The updated string with any replacement specifiers replaced + +### schemaRequiresTrueValue<S extends StrictRJSFSchema = RJSFSchema>() + +Check to see if a `schema` specifies that a value must be true. This happens when: + +- `schema.const` is truthy +- `schema.enum` == `[true]` +- `schema.anyOf` or `schema.oneOf` has a single value which recursively returns true +- `schema.allOf` has at least one value which recursively returns true + +#### Parameters + +- schema: S - The schema to check + +#### Returns + +- boolean: True if the schema specifies a value that must be true, false otherwise + +### shouldRender() + +Determines whether the given `component` should be rerendered by comparing its current set of props and state against the next set. +If either of those two sets are not the same, then the component should be rerendered. + +#### Parameters + +- component: React.Component - A React component being checked +- nextProps: any - The next set of props against which to check +- nextState: any - The next set of state against which to check + +#### Returns + +- True if boolean: the component should be re-rendered, false otherwise + +### titleId() + +Return a consistent `id` for the field title element. + +#### Parameters + +- id: IdSchema<T> | string - Either simple string id or an IdSchema from which to extract it + +#### Returns + +- string: The consistent id for the field title element from the given `id` + +### toConstant<S extends StrictRJSFSchema = RJSFSchema>() + +Returns the constant value from the schema when it is either a single value enum or has a const key. +Otherwise, throws an error. + +#### Parameters + +- schema: S - The schema from which to obtain the constant value + +#### Returns + +- string | number | boolean: The constant value for the schema + +#### Throws + +- Error when the schema does not have a constant value + +### toDateString() + +Returns a UTC date string for the given `dateObject`. +If `time` is false, then the time portion of the string is removed. + +#### Parameters + +- dateObject: DateObject - The `DateObject` to convert to a date string +- [time=true]: boolean - Optional flag used to remove the time portion of the date string if false + +#### Returns + +- string: The UTC date string + +### toErrorList() + +Converts an `errorSchema` into a list of `RJSFValidationErrors` + +#### Parameters + +- errorSchema: ErrorSchema<T> - The `ErrorSchema` instance to convert +- [fieldPath=[]]: string[] | undefined - The current field path, defaults to [] if not specified + +#### Returns + +- RJSFValidationErrors[]: The list of `RJSFValidationErrors` extracted from the `errorSchema` + +### toErrorSchema() + +Transforms a RJSF validation errors list into an `ErrorSchema` + +```ts +const changesThis = [ + { property: '.level1.level2[2].level3', message: 'err a', stack: '.level1.level2[2].level3 err a' }, + { property: '.level1.level2[2].level3', message: 'err b', stack: '.level1.level2[2].level3 err b' }, + { property: '.level1.level2[4].level3', message: 'err b', stack: '.level1.level2[4].level3 err b' }, +]; +const intoThis = { + level1: { + level2: { + 2: { level3: { errors: ['err a', 'err b'] } }, + 4: { level3: { errors: ['err b'] } }, + }, + }, +}; +``` + +#### Parameters + +- errors: RJSFValidationError[] - The list of RJSFValidationError objects + +#### Returns + +- ErrorSchema<T>: The `ErrorSchema` built from the list of `RJSFValidationErrors` + +#### unwrapErrorHandler() + +Unwraps the `errorHandler` structure into the associated `ErrorSchema`, stripping the `addError()` functions from it + +#### Parameters + +- errorHandler: FormValidation<T> - The `FormValidation` error handling structure + +#### Returns + +- ErrorSchema<T>: The `ErrorSchema` resulting from the stripping of the `addError()` function + +### utcToLocal() + +Converts a UTC date string into a local Date format + +#### Parameters + +- jsonDate: string - A UTC date string + +#### Returns + +- string: An empty string when `jsonDate` is falsey, otherwise a date string in local format + +### validationDataMerge() + +Merges the errors in `additionalErrorSchema` into the existing `validationData` by combining the hierarchies in the two `ErrorSchema`s and then appending the error list from the `additionalErrorSchema` obtained by calling `toErrorList()` on the `errors` in the `validationData`. +If no `additionalErrorSchema` is passed, then `validationData` is returned. + +#### Parameters + +- validationData: ValidationData<T> - The current `ValidationData` into which to merge the additional errors +- [additionalErrorSchema]: ErrorSchema<T> | undefined - The optional additional set of errors in an `ErrorSchema` + +#### Returns + +- ValidationData<T>: The `validationData` with the additional errors from `additionalErrorSchema` merged into it, if provided. + +### withIdRefPrefix<S extends StrictRJSFSchema = RJSFSchema>() + +Recursively prefixes all `$ref`s in a schema with the value of the `ROOT_SCHEMA_PREFIX` constant. +This is used in isValid to make references to the rootSchema + +#### Parameters + +- schemaNode: S - The object node to which a `ROOT_SCHEMA_PREFIX` is added when a `$ref` is part of it + +#### Returns + +- S: A copy of the `schemaNode` with updated `$ref`s + +## Validator-based utility functions + +### getDefaultFormState() + +Returns the superset of `formData` that includes the given set updated to include any missing fields that have computed to have defaults provided in the `schema`. + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- theSchema: S - The schema for which the default state is desired +- [formData]: T | undefined - The current formData, if any, onto which to provide any missing defaults +- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s +- [includeUndefinedValues=false]: boolean | "excludeObjectChildren" - Optional flag, if true, cause undefined values to be added as defaults. If "excludeObjectChildren", cause undefined values for this object and pass `includeUndefinedValues` as false when computing defaults for any nested object properties. +- [experimental_defaultFormStateBehavior]: Experimental_DefaultFormStateBehavior - See `Form` documentation for the [experimental_defaultFormStateBehavior](./form-props.md#experimental_defaultFormStateBehavior) prop +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- T: The resulting `formData` with all the defaults provided + +### getDisplayLabel() + +Determines whether the combination of `schema` and `uiSchema` properties indicates that the label for the `schema` should be displayed in a UI. + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: S - The schema for which the display label flag is desired +- [uiSchema={}]: UiSchema - The UI schema from which to derive potentially displayable information +- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s +- [globalOptions={}]: GlobalUISchemaOptions - The optional Global UI Schema from which to get any fallback `xxx` options +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- boolean: True if the label should be displayed or false if it should not + +### getClosestMatchingOption() + +Determines which of the given `options` provided most closely matches the `formData`. +Returns the index of the option that is valid and is the closest match, or 0 if there is no match. + +The closest match is determined using the number of matching properties, and more heavily favors options with matching readOnly, default, or const values. + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- rootSchema: S - The root schema, used to primarily to look up `$ref`s +- [formData]: T | undefined - The current formData, if any, used to figure out a match +- options: S[] - The list of options to find a matching options from +- [selectedOption=-1]: number - The index of the currently selected option, defaulted to -1 if not specified +- [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- number: The index of the option that is the closest match to the `formData` or the `selectedOption` if no match + +### getFirstMatchingOption() + +Given the `formData` and list of `options`, attempts to find the index of the first option that matches the data. +Always returns the first option if there is nothing that matches. + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- [formData]: T | undefined - The current formData, if any, used to figure out a match +- options: S[] - The list of options to find a matching options from +- rootSchema: S - The root schema, used to primarily to look up `$ref`s +- [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected + +#### Returns + +- number: The index of the first matched option or 0 if none is available + +### getMatchingOption() + +Given the `formData` and list of `options`, attempts to find the index of the option that best matches the data. +Deprecated, use `getFirstMatchingOption()` instead. + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- [formData]: T | undefined - The current formData, if any, used to figure out a match +- options: S[] - The list of options to find a matching options from +- rootSchema: S - The root schema, used to primarily to look up `$ref`s +- [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected + +#### Returns + +- number: The index of the matched option or 0 if none is available + +### isFilesArray() + +Checks to see if the `schema` and `uiSchema` combination represents an array of files + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: S - The schema for which check for array of files flag is desired +- [uiSchema={}]: UiSchema - The UI schema from which to check the widget +- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- boolean: True if schema/uiSchema contains an array of files, otherwise false + +### isMultiSelect() + +Checks to see if the `schema` combination represents a multi-select + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: S - The schema for which check for a multi-select flag is desired +- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- boolean: True if schema contains a multi-select, otherwise false + +### isSelect() + +Checks to see if the `schema` combination represents a select + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- theSchema: S - The schema for which check for a select flag is desired +- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- boolean: True if schema contains a select, otherwise false + +### mergeValidationData() + +Merges the errors in `additionalErrorSchema` into the existing `validationData` by combining the hierarchies in the two `ErrorSchema`s and then appending the error list from the `additionalErrorSchema` obtained by calling `validator.toErrorList()` onto the `errors` in the `validationData`. +If no `additionalErrorSchema` is passed, then `validationData` is returned. + +> NOTE: This is function is deprecated. Use the `validationDataMerge()` function exported from `@rjsf/utils` instead. This function will be +> removed in the next major release. + +#### Parameters + +- validator: ValidatorType<T, S, F> - An implementation of the `ValidatorType` interface that will be used to convert an ErrorSchema to a list of errors +- validationData: ValidationData<T> - The current `ValidationData` into which to merge the additional errors +- [additionalErrorSchema]: ErrorSchema<T> | undefined - The additional set of errors in an `ErrorSchema` + +#### Returns + +- ValidationData<T>: The `validationData` with the additional errors from `additionalErrorSchema` merged into it, if provided. + +### retrieveSchema() + +Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies +resolved and merged into the `schema` given a `validator`, `rootSchema` and `rawFormData` that is used to do the +potentially recursive resolution. + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be forwarded to all the APIs +- schema: S - The schema for which retrieving a schema is desired +- [rootSchema={}]: S - The root schema that will be forwarded to all the APIs +- [rawFormData]: T | undefined - The current formData, if any, to assist retrieving a schema +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- RJSFSchema: The schema having its conditions, additional properties, references and dependencies resolved + +### sanitizeDataForNewSchema() + +Sanitize the `data` associated with the `oldSchema` so it is considered appropriate for the `newSchema`. +If the new schema does not contain any properties, then `undefined` is returned to clear all the form data. +Due to the nature of schemas, this sanitization happens recursively for nested objects of data. +Also, any properties in the old schema that are non-existent in the new schema are set to `undefined`. + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- rootSchema: S - The root JSON schema of the entire form +- [newSchema]: S | undefined - The new schema for which the data is being sanitized +- [oldSchema]: S | undefined - The old schema from which the data originated +- [data={}]: any - The form data associated with the schema, defaulting to an empty object when undefined +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- T: The new form data, with all the fields uniquely associated with the old schema set to `undefined`. Will return `undefined` if the new schema is not an object containing properties. + +### toIdSchema() + +Generates an `IdSchema` object for the `schema`, recursively + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: S - The schema for which the `IdSchema` is desired +- [id]: string | null - The base id for the schema +- [rootSchema]: S | undefined- The root schema, used to primarily to look up `$ref`s +- [formData]: T | undefined - The current formData, if any, to assist retrieving a schema +- [idPrefix='root']: string - The prefix to use for the id +- [idSeparator='_']: string - The separator to use for the path segments in the id +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- IDSchema<T>: The `IdSchema` object for the `schema` + +### toPathSchema() + +Generates an `PathSchema` object for the `schema`, recursively + +#### Parameters + +- validator: ValidatorType - An implementation of the `ValidatorType` interface that will be used when necessary +- schema: S - The schema for which the `PathSchema` is desired +- [name='']: string - The base name for the schema +- [rootSchema]: S | undefined - The root schema, used to primarily to look up `$ref`s +- [formData]: T | undefined - The current formData, if any, to assist retrieving a schema +- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See `Form` documentation for the [experimental_customMergeAllOf](./form-props.md#experimental_custommergeallof) prop + +#### Returns + +- PathSchema<T> - The `PathSchema` object for the `schema` + +## Schema utils creation function + +### createSchemaUtils() + +Creates a `SchemaUtilsType` interface that is based around the given `validator` and `rootSchema` parameters. +The resulting interface implementation will forward the `validator` and `rootSchema` to all the wrapped APIs. + +#### Parameters + +- validator: ValidatorType - an implementation of the `ValidatorType` interface that will be forwarded to all the APIs +- rootSchema: S - The root schema that will be forwarded to all the APIs + +#### Returns + +- SchemaUtilsType - An implementation of a `SchemaUtilsType` interface + +## ErrorSchema builder class + +### ErrorSchemaBuilder<T = any>(initialSchema?: ErrorSchema<T>) constructor + +The `ErrorSchemaBuilder<T>` is used to build an `ErrorSchema<T>` since the definition of the `ErrorSchema` type is designed for reading information rather than writing it. +Use this class to add, replace or clear errors in an error schema by using either dotted path or an array of path names. +Once you are done building the `ErrorSchema`, you can get the result and/or reset all the errors back to an initial set and start again. + +#### Parameters + +- [initialSchema]: ErrorSchema<T> | undefined - The optional set of initial errors, that will be cloned into the class + +#### Returns + +- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class + +### ErrorSchema getter function + +Returns the `ErrorSchema` that has been updated by the methods of the `ErrorSchemaBuilder` + +Usage: + +```ts +import { ErrorSchemaBuilder, ErrorSchema } from "@rjsf/utils"; + +const builder = new ErrorSchemaBuilder(); + +// Do some work using the builder +... + +const errorSchema: ErrorSchema = builder.ErrorSchema; +``` + +### resetAllErrors() + +Resets all errors in the `ErrorSchemaBuilder` back to the `initialSchema` if provided, otherwise an empty set. + +#### Parameters + +- [initialSchema]: ErrorSchema<T> | undefined - The optional set of initial errors, that will be cloned into the class + +#### Returns + +- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class + +### addErrors() + +Adds the `errorOrList` to the list of errors in the `ErrorSchema` at either the root level or the location within the schema described by the `pathOfError`. +For more information about how to specify the path see the [eslint lodash plugin docs](https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/path-style.md). + +#### Parameters + +- errorOrList: string | string[] - The error or list of errors to add into the `ErrorSchema` +- [pathOfError]: string | (string | number)[] | undefined - The optional path into the `ErrorSchema` at which to add the error(s) + +#### Returns + +- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class + +### setErrors() + +Sets/replaces the `errorOrList` as the error(s) in the `ErrorSchema` at either the root level or the location within the schema described by the `pathOfError`. +For more information about how to specify the path see the [eslint lodash plugin docs](https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/path-style.md). + +#### Parameters + +- errorOrList: string | string[] - The error or list of errors to add into the `ErrorSchema` +- [pathOfError]: string | (string | number)[] | undefined - The optional path into the `ErrorSchema` at which to add the error(s) + +#### Returns + +- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class + +### clearErrors() + +Clears the error(s) in the `ErrorSchema` at either the root level or the location within the schema described by the `pathOfError`. +For more information about how to specify the path see the [eslint lodash plugin docs](https://github.com/wix/eslint-plugin-lodash/blob/master/docs/rules/path-style.md). + +#### Parameters + +- [pathOfError]: string | (string | number)[] | undefined - The optional path into the `ErrorSchema` at which to add the error(s) + +#### Returns + +- ErrorSchemaBuilder<T> - The instance of the `ErrorSchemaBuilder` class diff --git a/packages/docs/versioned_docs/version-5.24.10/api-reference/validator-ajv8.md b/packages/docs/versioned_docs/version-5.24.10/api-reference/validator-ajv8.md new file mode 100644 index 0000000000..2e9cedffed --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/api-reference/validator-ajv8.md @@ -0,0 +1,57 @@ +# @rjsf/validator-ajv8 APIs + +In RJSF version 5, the original, embedded AJV 6 validator implementation from earlier versions was extracted into its own package, `@rjsf/validator-ajv6`, which was immediately deprecated since AJV 6 is no longer getting maintenance updates. +A new `@rjsf/validator-ajv8` package was added that uses the AJV 8 package, including adding support for using precompiled validators. +Below are the exported API functions that are provided by this package. +See the [Validation documentation](../usage/validation.md) for examples of using these APIs. + +## Types + +There are a few Typescript types that are exported by `@rjsf/validator-ajv8` in support of the APIs. + +These types can be found on GitHub [here](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/validator-ajv8/src/types.ts). + +## APIs + +### customizeValidator() + +Creates and returns a customized implementation of the `ValidatorType` with the given customization `options` if provided. +If a `localizer` is provided, it is used to translate the messages generated by the underlying AJV validation. + +#### Parameters + +- [options={}]: CustomValidatorOptionsType - The optional map of `CustomValidatorOptionsType` options that are used to create the `ValidatorType` instance +- [localizer]: Localizer | undefined - If provided, is used to localize a list of Ajv `ErrorObject`s after running the form validation using AJV + +#### Returns + +- AJV8Validator<T, S, F>: The custom validator implementation resulting from the set of parameters provided + +### compileSchemaValidators<S extends StrictRJSFSchema = RJSFSchema>() + +The function used to compile a schema into an output file in the form that allows it to be used as a precompiled validator. +The main reasons for using a precompiled validator is reducing code size, improving validation speed and, most importantly, avoiding dynamic code compilation when prohibited by a browser's Content Security Policy. +For more information about AJV code compilation see: https://ajv.js.org/standalone.html + +#### Parameters + +- schema: S - The schema to be compiled into a set of precompiled validators functions +- output: string - The name of the file into which the precompiled validator functions will be generated +- [options={}]: CustomValidatorOptionsType - The set of `CustomValidatorOptionsType` information used to alter the AJV validator used for compiling the schema. They are the same options that are passed to the `customizeValidator()` function in order to modify the behavior of the regular AJV-based validator. + +### createPrecompiledValidator() + +Creates and returns a `ValidatorType` interface that is implemented with a precompiled validator. +If a `localizer` is provided, it is used to translate the messages generated by the underlying AJV validation. + +> NOTE: The `validateFns` parameter is an object obtained by importing from a precompiled validation file created via the `compileSchemaValidators()` function. + +#### Parameters + +- validateFns: ValidatorFunctions - The map of the validation functions that are created by the `compileSchemaValidators()` function +- rootSchema: S - The root schema that was used with the `compileSchemaValidators()` function +- [localizer]: Localizer | undefined - If provided, is used to localize a list of Ajv `ErrorObject`s after running the form validation using AJV + +#### Returns + +- ValidatorType<T, S, F>: The precompiled validator implementation resulting from the set of parameters provided diff --git a/packages/docs/versioned_docs/version-5.24.10/contributing.md b/packages/docs/versioned_docs/version-5.24.10/contributing.md new file mode 100644 index 0000000000..99fcb0145c --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/contributing.md @@ -0,0 +1,182 @@ +# Contributing + +## Development server + +We are using `Vite` to power our `playground`, which caches all the built `@rjsf/*` distributions. +In order to test the `playground` locally after a new clone or fresh pull from `main`, run the following from the root directory of the monorepo: + +```bash +npm install +npm run build +cd packages/playground +npm start +``` + +This will start the live development server showcasing components at [localhost:8080](http://localhost:8080). + +Whenever you make changes to source code, stop the running playground and return to the root directory and rerun `npm run build`. +Thanks to `nx` caching, this should only rebuild what is necessary. +After the build is complete, return to the root of the `playground` and restart the server via `npm start`. + +### First time step + +If this is the first time you have cloned the repo, run the `npm run prepare` script that will set up `husky` to provide a git precommit hook that will format and lint any code you have added to a PR. + +### Optional development process + +With the large number of packages, sometimes running `npm run build` or `npm start` from the root directory will overwhelm an underpowered computer. +If that is the situation for you, you can instead use `npm run build-serial` to build the packages one at a time instead of all at once. +Also, if you are only working on one package, you can `npm run build` and `npm run test` from within the subdirectory. +Finally, you can simply `npm start` inside of the `playground` directory to test changes if you have already built all of your packages, without needing to watch all of the packages via the root directory `npm start`. + +## Cloud builds + +When building in environments with limited memory, such as Netlify, it's recommended to use `npm run build-serial` that builds the packages serially. + +## Coding style + +All the JavaScript/Typescript code in this project conforms to the [prettier](https://github.com/prettier/prettier) coding style. +Code is automatically prettified upon commit using precommit hooks, assuming you followed the `First time step` above. + +You can also run `npm cs-format` within any package directory you are changing. + +## Documentation + +We use [Docusaurus](https://docusaurus.io/) to build our documentation. To run documentation locally, run: + +```bash +cd packages/docs +npm start +``` + +Documentation will be served on [localhost:3000](http://localhost:3000). + +## Tests + +You can run all tests from the root directory OR from `packages` subdirectory using the following command: + +```bash +npm run test +``` + +### Snapshot testing + +All the themes, including `core` use snapshot testing (NOTE: `core` also has extensive non-snapshot tests). +The source-code of these snapshot tests reside in the `core` package in the `testSnap` directory and are shared with all the themes. +In order to support the various themes, the code for the tests are actually functions that take two parameters: + +- `Form`: ComponentType<FormProps> - The component from the theme implementation +- `[customOptions]`: { [key: string]: TestRendererOptions } - an optional map of `react-test-renderer` `TestRendererOptions` implementations that some themes need to be able properly run + +There are functions in the `testSnap` directory: `arrayTests`, `formTests` and `objectTests`, each with its own definition of `customOptions` + +Each theme will basically run these functions by creating a `Xxx.test.tsx` file (where `Xxx` is `Array`, `Form` or `Object`) that looks like the following: + +```tsx +import { arrayTests } from '@rjsf/snapshot-tests'; // OR +// import { formTests } from '@rjsf/snapshot-tests'; +// import { objectTests } from '@rjsf/snapshot-tests'; + +import Form from '../src'; + +arrayTests(Form); // OR +// formTests(Form); +// objectTests(Form); +``` + +Anytime you add a new feature, be sure to update the appropriate `xxxTests()` function in the `testSnap` directory and do `npm run test` from the root directory to update all the snapshots. +If you add a theme-only feature, it is ok to update the appropriate `Xxx.test.tsx` file to add (or update) the theme-specific `describe()` block. +For example: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import { arrayTests } from '@rjsf/snapshot-tests'; + +import Form from '../src'; + +formTests(Form); + +describe('Theme specific tests', () => { + it('test a theme-specific option', () => { + const schema: RJSFSchema = { + type: 'object', + properties: { + name: { + type: 'string', + }, + }, + }; + const uiSchema: UiSchema = { + // Enable the theme specific feature + }; + const tree = renderer.create().toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); +``` + +See the `antd` `Form.test.tsx` for a specific example of this. + +### Code coverage + +Code coverage reports are currently available only for the `@rjsf/core` theme package. +They are generated using [nyc](https://github.com/istanbuljs/nyc) each time the `npm test-coverage` script is run. +The full report can be seen by opening `./coverage/lcov-report/index.html`. + +#### Utils and validator-ajvX code coverage + +100% code coverage is required by the `@rjsf/utils` and `@rjsf/validator-ajv6` and `@rjsf/validator-ajv8` tests. +If you make changes to those libraries, you will have to maintain that coverage, otherwise the tests will fail. + +> NOTE: All three of these directories share the same tests for verifying `validator` based APIs. See the documentation in the `getTestValidator()` functions for more information. + +## Releasing + +To release, go to the main branch (NOT a fork) and then create a new branch with the version number (with an `rc` prefix instead of `v`). +For instance if you are about to create the new `5.100.10` branch, then you would run the following commands: + +```bash +git checkout -b rc5.100.10 +git push +npx lerna version +npm run post-versioning +``` + +Make sure you use [semver](https://semver.org/) for version numbering when selecting the version. +The `npx lerna version` command will create a new version tag and push it to GitHub. + +The `npm run post-versioning` script will update the peer dependencies in all of the `packages/*/package.json` files if necessary. +It will then clean up the `node_modules` directories and rerun `npm install` to update the `package-lock.json` files. +Finally, it creates and pushes a new commit with those `package.json` and `package-lock.json` files up to GitHub. + +> NOTE: this command will take a while, be patient + +Then, make a PR to main. Merge the PR into main -- make sure you use "merge commit", not squash and merge, so that +the original commit where the tag was based on is still present in the main branch. + +Then, create a release in the GitHub "Releases" tab, select the new tag that you have added, +and add a description of the changes in the new release. You can copy +the latest changelog entry in `CHANGELOG.md` to make the release notes, and update as necessary. + +This will trigger a GitHub Actions pipeline that will build and publish all packages to npm. + +The package is published through an automation token belonging to the +[rjsf-bot](https://www.npmjs.com/~rjsf-bot) user on npm. This token +is stored as the `NPM_TOKEN` secret on GitHub Actions. + +### Releasing docs + +Docs are automatically published to GitHub Pages when the `main` branch is updated. + +We are currently in the process of automatically configuring versionable documentation on our new docs site. + +### Releasing the playground + +The playground automatically gets deployed from GitHub Pages. + +If you need to manually publish the latest playground to [https://rjsf-team.github.io/react-jsonschema-form/](https://rjsf-team.github.io/react-jsonschema-form/), though, run: + +```bash +cd packages/playground +npm run publish-to-gh-pages +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/json-schema/arrays.md b/packages/docs/versioned_docs/version-5.24.10/json-schema/arrays.md new file mode 100644 index 0000000000..e8a4e1262b --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/json-schema/arrays.md @@ -0,0 +1,336 @@ +# Arrays + +Arrays are defined with a type equal to `array`, and array items' schemas are specified in the `items` keyword. + +## Arrays of a single field + +Arrays of a single field type can be specified as follows: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +render(, document.getElementById('app')); +``` + +## Arrays of objects + +Arrays of objects can be specified as follows: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'object', + properties: { + name: { + type: 'string', + }, + }, + }, +}; + +render(, document.getElementById('app')); +``` + +## uiSchema for array items + +To specify a uiSchema that applies to array items, specify the uiSchema value within the `items` property: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +const uiSchema = { + items: { + 'ui:widget': 'textarea', + }, +}; + +render(, document.getElementById('app')); +``` + +## The `additionalItems` keyword + +The `additionalItems` keyword allows the user to add additional items of a given schema. For example: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, + additionalItems: { + type: 'boolean', + }, +}; + +render(, document.getElementById('app')); +``` + +## Array item uiSchema options + +Any of these options can be set globally if they are contained within the `ui:globalOptions` block. +They can also be overridden on a per-field basis inside a `ui:options` block as shown below. + +### `orderable` option + +Array items are orderable by default, and react-jsonschema-form renders move up/down buttons alongside them. The uiSchema `orderable` options allows you to disable ordering: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +const uiSchema: UiSchema = { + 'ui:options': { + orderable: false, + }, +}; + +render(, document.getElementById('app')); +``` + +### `addable` option + +If either `items` or `additionalItems` contains a schema object, an add button for new items is shown by default. You can turn this off with the `addable` option in `uiSchema`: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +const uiSchema: UiSchema = { + 'ui:options': { + addable: false, + }, +}; + +render(, document.getElementById('app')); +``` + +### `copyable` option + +A copy button is **NOT** shown by default for an item if `items` contains a schema object, or the item is an `additionalItems` instance. +You can turn this **ON** with the `copyable` option in `uiSchema`: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +const uiSchema: UiSchema = { + 'ui:options': { + copyable: true, + }, +}; + +render(, document.getElementById('app')); +``` + +### `removable` option + +A remove button is shown by default for an item if `items` contains a schema object, or the item is an `additionalItems` instance. You can turn this off with the `removable` option in `uiSchema`: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + }, +}; + +const uiSchema: UiSchema = { + 'ui:options': { + removable: false, + }, +}; + +render(, document.getElementById('app')); +``` + +## Multiple-choice list + +The default behavior for array fields is a list of text inputs with add/remove buttons. There are two alternative widgets for picking multiple elements from a list of choices. Typically, this applies when a schema has an `enum` list for the `items` property of an `array` field, and the `uniqueItems` property set to `true`. + +Example: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + title: 'A multiple-choice list', + items: { + type: 'string', + enum: ['foo', 'bar', 'fuzz', 'qux'], + }, + uniqueItems: true, +}; + +render(, document.getElementById('app')); +``` + +By default, this will render a multiple select box. If you prefer a list of checkboxes, just set the uiSchema `ui:widget` directive to `checkboxes` for that field: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + title: 'A multiple-choice list', + items: { + type: 'string', + enum: ['foo', 'bar', 'fuzz', 'qux'], + }, + uniqueItems: true, +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'checkboxes', +}; + +render(, document.getElementById('app')); +``` + +## Custom widgets + +In addition to [ArrayFieldTemplate](../advanced-customization/custom-templates.md#arrayfieldtemplate) you use your own widget by providing it to the uiSchema with the property of `ui:widget`. + +Example: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const CustomSelectComponent = (props) => { + return ( + + ); +}; + +const schema: RJSFSchema = { + type: 'array', + title: 'A multiple-choice list', + items: { + type: 'string', + }, +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'CustomSelect', +}; + +const widgets = { + CustomSelect: CustomSelectComponent, +}; + +render( + , + document.getElementById('app') +); +``` + +## Specifying the minimum or maximum number of items + +Note that when an array property is marked as `required`, an empty array is considered valid. If the array needs to be populated, you can specify the minimum number of items using the `minItems` property. + +Example: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + minItems: 2, + title: 'A multiple-choice list', + items: { + type: 'string', + enum: ['foo', 'bar', 'fuzz', 'qux'], + }, + uniqueItems: true, +}; + +render(, document.getElementById('app')); +``` + +You can also specify the maximum number of items in an array using the `maxItems` property. + +## Inline checkboxes + +By default, checkboxes are stacked. If you prefer them inline, set the `inline` property to `true`: + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'array', + minItems: 2, + title: 'A multiple-choice list', + items: { + type: 'string', + enum: ['foo', 'bar', 'fuzz', 'qux'], + }, + uniqueItems: true, +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'checkboxes', + 'ui:options': { + inline: true, + }, +}; + +render(, document.getElementById('app')); +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/json-schema/definitions.md b/packages/docs/versioned_docs/version-5.24.10/json-schema/definitions.md new file mode 100644 index 0000000000..980aa98d22 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/json-schema/definitions.md @@ -0,0 +1,31 @@ +# Schema definitions and references + +This library partially supports [inline schema definition dereferencing](http://json-schema.org/draft/2019-09/json-schema-core.html#ref), which allows you to re-use parts of your schema: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + definitions: { + address: { + type: 'object', + properties: { + street_address: { type: 'string' }, + city: { type: 'string' }, + state: { type: 'string' }, + }, + required: ['street_address', 'city', 'state'], + }, + }, + type: 'object', + properties: { + billing_address: { $ref: '#/definitions/address' }, + shipping_address: { $ref: '#/definitions/address' }, + }, +}; + +render(, document.getElementById('app')); +``` + +Note that this library only supports local definition referencing. The value in the `$ref` keyword should be a [JSON Pointer](https://tools.ietf.org/html/rfc6901) in URI fragment identifier format. diff --git a/packages/docs/versioned_docs/version-5.24.10/json-schema/dependencies.md b/packages/docs/versioned_docs/version-5.24.10/json-schema/dependencies.md new file mode 100644 index 0000000000..43a0789180 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/json-schema/dependencies.md @@ -0,0 +1,165 @@ +# Dependencies + +react-jsonschema-form supports the `dependencies` keyword from an earlier draft of JSON Schema (note that this is not part of the latest JSON Schema spec, though). Dependencies can be used to create dynamic schemas that change fields based on what data is entered. + +## Property dependencies + +This library supports conditionally making fields required based on the presence of other fields. + +### Unidirectional + +In the following example the `billing_address` field will be required if `credit_card` is defined. + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + + properties: { + name: { type: 'string' }, + credit_card: { type: 'number' }, + billing_address: { type: 'string' }, + }, + + required: ['name'], + + dependencies: { + credit_card: ['billing_address'], + }, +}; + +render(, document.getElementById('app')); +``` + +### Bidirectional + +In the following example the `billing_address` field will be required if `credit_card` is defined and the `credit_card` +field will be required if `billing_address` is defined, making them both required if either is defined. + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + + properties: { + name: { type: 'string' }, + credit_card: { type: 'number' }, + billing_address: { type: 'string' }, + }, + + required: ['name'], + + dependencies: { + credit_card: ['billing_address'], + billing_address: ['credit_card'], + }, +}; + +render(, document.getElementById('app')); +``` + +_(Sample schemas courtesy of the [Space Telescope Science Institute](https://spacetelescope.github.io/understanding-json-schema/reference/object.html#property-dependencies))_ + +## Schema dependencies + +This library also supports modifying portions of a schema based on form data. + +### Conditional + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + + properties: { + name: { type: 'string' }, + credit_card: { type: 'number' }, + }, + + required: ['name'], + + dependencies: { + credit_card: { + properties: { + billing_address: { type: 'string' }, + }, + required: ['billing_address'], + }, + }, +}; + +render(, document.getElementById('app')); +``` + +In this example the `billing_address` field will be displayed in the form if `credit_card` is defined. + +_(Sample schemas courtesy of the [Space Telescope Science Institute](https://spacetelescope.github.io/understanding-json-schema/reference/object.html#schema-dependencies))_ + +### Dynamic + +The JSON Schema standard says that the dependency is triggered if the property is present. However, sometimes it's useful to have more sophisticated rules guiding the application of the dependency. For example, maybe you have three possible values for a field, and each one should lead to adding a different question. For this, we support a very restricted use of the `oneOf` keyword. + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Person', + type: 'object', + properties: { + 'Do you have any pets?': { + type: 'string', + enum: ['No', 'Yes: One', 'Yes: More than one'], + default: 'No', + }, + }, + required: ['Do you have any pets?'], + dependencies: { + 'Do you have any pets?': { + oneOf: [ + { + properties: { + 'Do you have any pets?': { + enum: ['No'], + }, + }, + }, + { + properties: { + 'Do you have any pets?': { + enum: ['Yes: One'], + }, + 'How old is your pet?': { + type: 'number', + }, + }, + required: ['How old is your pet?'], + }, + { + properties: { + 'Do you have any pets?': { + enum: ['Yes: More than one'], + }, + 'Do you want to get rid of any?': { + type: 'boolean', + }, + }, + required: ['Do you want to get rid of any?'], + }, + ], + }, + }, +}; + +render(, document.getElementById('app')); +``` + +In this example the user is prompted with different follow-up questions dynamically based on their answer to the first question. + +In these examples, the "Do you have any pets?" question is validated against the corresponding property in each schema in the `oneOf` array. If exactly one matches, the rest of that schema is merged with the existing schema. diff --git a/packages/docs/versioned_docs/version-5.24.10/json-schema/index.mdx b/packages/docs/versioned_docs/version-5.24.10/json-schema/index.mdx new file mode 100644 index 0000000000..21f5e14f8c --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/json-schema/index.mdx @@ -0,0 +1,10 @@ +--- +title: JSON Schema +description: Documentation for how to use JSON Schema constructs in react-jsonschema-form., +--- + +import DocCardList from '@theme/DocCardList'; + +

{frontMatter.description}

+ + \ No newline at end of file diff --git a/packages/docs/versioned_docs/version-5.24.10/json-schema/objects.md b/packages/docs/versioned_docs/version-5.24.10/json-schema/objects.md new file mode 100644 index 0000000000..c7672ff7dc --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/json-schema/objects.md @@ -0,0 +1,131 @@ +# Objects + +## Object properties + +Objects are defined with a type equal to `object` and properties specified in the `properties` keyword. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'My title', + description: 'My description', + type: 'object', + properties: { + name: { + type: 'string', + }, + age: { + type: 'number', + }, + }, +}; + +render(, document.getElementById('app')); +``` + +## Required properties + +You can specify which properties are required using the `required` attribute: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'My title', + description: 'My description', + type: 'object', + properties: { + name: { + type: 'string', + }, + age: { + type: 'number', + }, + }, + required: ['name'], +}; + +render(, document.getElementById('app')); +``` + +## Specifying property order + +Since the order of object properties in Javascript and JSON is not guaranteed, the `uiSchema` object spec allows you to define the order in which properties are rendered using the `ui:order` property: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + foo: { type: 'string' }, + bar: { type: 'string' }, + }, +}; + +const uiSchema: UiSchema = { + 'ui:order': ['bar', 'foo'], +}; + +render(, document.getElementById('app')); +``` + +If a guaranteed fixed order is only important for some fields, you can insert a wildcard `"*"` item in your `ui:order` definition. All fields that are not referenced explicitly anywhere in the list will be rendered at that point: + +```ts +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:order': ['bar', '*'], +}; +``` + +## Additional properties + +The `additionalProperties` keyword allows the user to add properties with arbitrary key names. Set this keyword equal to a schema object: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + name: { + type: 'string', + }, + }, + additionalProperties: { + type: 'number', + enum: [1, 2, 3], + }, +}; + +render(, document.getElementById('app')); +``` + +In this way, an add button for new properties is shown by default. + +You can also define `uiSchema` options for `additionalProperties` by setting the `additionalProperties` attribute in the `uiSchema`. + +### `expandable` option + +You can turn support for `additionalProperties` off with the `expandable` option in `uiSchema`: + +```ts +import { UiSchema } from '@rjsf/utils'; + +const uiSchema: UiSchema = { + 'ui:options': { + expandable: false, + }, +}; +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/json-schema/oneof.md b/packages/docs/versioned_docs/version-5.24.10/json-schema/oneof.md new file mode 100644 index 0000000000..d2545af72c --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/json-schema/oneof.md @@ -0,0 +1,94 @@ +# oneOf, anyOf, and allOf + +react-jsonschema-form supports custom widgets for oneOf, anyOf, and allOf. + +- A schema with `oneOf` is valid if _exactly one_ of the subschemas is valid. +- A schema with `anyOf` is valid if _at least one_ of the subschemas is valid. +- A schema with `allOf` is valid if _all_ of the subschemas are valid. + +## oneOf + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + oneOf: [ + { + properties: { + lorem: { + type: 'string', + }, + }, + required: ['lorem'], + }, + { + properties: { + ipsum: { + type: 'string', + }, + }, + required: ['ipsum'], + }, + ], +}; + +render(, document.getElementById('app')); +``` + +## anyOf + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + anyOf: [ + { + properties: { + lorem: { + type: 'string', + }, + }, + required: ['lorem'], + }, + { + properties: { + lorem: { + type: 'string', + }, + ipsum: { + type: 'string', + }, + }, + }, + ], +}; + +render(, document.getElementById('app')); +``` + +## allOf + +When `allOf` is specified in a schema, react-jsonschema-form uses the [json-schema-merge-allof](https://github.com/mokkabonna/json-schema-merge-allof) library to merge the specified subschemas to create a combined subschema that is valid. For example, the below schema evaluates to a combined subschema of `{type: "boolean"}`: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'Field', + allOf: [ + { + type: ['string', 'boolean'], + }, + { + type: 'boolean', + }, + ], +}; + +render(, document.getElementById('app')); +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/json-schema/single.md b/packages/docs/versioned_docs/version-5.24.10/json-schema/single.md new file mode 100644 index 0000000000..c3bf7fffbb --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/json-schema/single.md @@ -0,0 +1,173 @@ +# Single fields + +The simplest example of a JSON Schema contains only a single field. The field type is determined by the `type` parameter. + +## Field types + +The base field types in JSON Schema include: + +- `string` +- `number` +- `integer` +- `boolean` +- `null` + +Here is an example of a string field: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +## Titles and descriptions + +Fields can have titles and descriptions specified by the `title` keyword in the schema and the `description` keyword in the schema, respectively. These two can also be overridden by the `ui:title` and `ui:description` keywords in the uiSchema. + +Description can render markdown. This feature is disabled by default. It needs to be enabled by the `ui:enableMarkdownInDescription` keyword and setting to `true`. Read more about markdown options in the `markdown-to-jsx` official [docs](https://markdown-to-jsx.quantizor.dev/). + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + title: 'My form', + description: 'My description', + type: 'string', +}; + +render(, document.getElementById('app')); +``` + +## Enumerated values + +All base schema types support the `enum` attribute, which restricts the user to select among a list of options. For example: + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + enum: ['one', 'two', 'three'], +}; + +render(, document.getElementById('app')); +``` + +### Custom labels for `enum` fields + +JSON Schema supports the following approaches to enumerations using `oneOf`/`anyOf`; react-jsonschema-form supports it as well. + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'number', + anyOf: [ + { + type: 'number', + title: 'one', + enum: [1], + }, + { + type: 'number', + title: 'two', + enum: [2], + }, + { + type: 'number', + title: 'three', + enum: [3], + }, + ], +}; + +render(, document.getElementById('app')); +``` + +```tsx +import { RJSFSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'number', + oneOf: [ + { const: 1, title: 'one' }, + { const: 2, title: 'two' }, + { const: 3, title: 'three' }, + ], +}; + +render(, document.getElementById('app')); +``` + +In your JSON Schema, you may also specify `enumNames`, a non-standard field which RJSF can use to label an enumeration. **This behavior is deprecated and will be removed in a future major release of RJSF. Use the "ui:enumNames" property in the uiSchema instead.** + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'number', + enum: [1, 2, 3], + enumNames: ['one', 'two', 'three'], +}; +render(, document.getElementById('app')); +``` + +Same example using the `uiSchema`'s `ui:enumNames` instead. + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'number', + enum: [1, 2, 3], +}; +const uiSchema: UiSchema = { + 'ui:enumNames': ['one', 'two', 'three'], +}; +render(, document.getElementById('app')); +``` + +### Disabled attribute for `enum` fields + +To disable an option, use the `ui:enumDisabled` property in the uiSchema. + +```tsx +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'boolean', + enum: [true, false], +}; + +const uiSchema: UiSchema = { + 'ui:enumDisabled': [true], +}; + +render(, document.getElementById('app')); +``` + +## Nullable types + +JSON Schema supports specifying multiple types in an array; however, react-jsonschema-form only supports a restricted subset of this -- nullable types, in which an element is either a given type or equal to null. + +```tsx +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: ['string', 'null'], +}; + +render(, document.getElementById('app')); +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/migration-guides/index.mdx b/packages/docs/versioned_docs/version-5.24.10/migration-guides/index.mdx new file mode 100644 index 0000000000..6da0f3631b --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/migration-guides/index.mdx @@ -0,0 +1,10 @@ +--- +title: Migration Guides +description: Guides for upgrading to new major versions of react-jsonschema-form +--- + +import DocCardList from '@theme/DocCardList'; + +

{frontMatter.description}

+ + \ No newline at end of file diff --git a/packages/docs/versioned_docs/version-5.24.10/migration-guides/v2.x upgrade guide.md b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v2.x upgrade guide.md new file mode 100644 index 0000000000..3a8be4046e --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v2.x upgrade guide.md @@ -0,0 +1,34 @@ +# 2.x Upgrade Guide + +## Changes from v1 -> v2 + +### Breaking changes + +- We now officially support the @rjsf/material-ui theme. We use a monorepo with Lerna and have published two packages (@rjsf/core and @rjsf/material-ui) with this version number. Note that react-jsonschema-form has been renamed to @rjsf/core ([#1642](https://github.com/rjsf-team/react-jsonschema-form/pull/1642)) +- Combine all themes into a single playground ([#1539](https://github.com/rjsf-team/react-jsonschema-form/pull/1539), [#1607](https://github.com/rjsf-team/react-jsonschema-form/pull/1607), [#1623](https://github.com/rjsf-team/react-jsonschema-form/pull/1623)) +- Remove ui:order console warning about extraneous properties ([#1508](https://github.com/rjsf-team/react-jsonschema-form/pull/1508)) +- Capitalized Yes and No defaults ([#1395](https://github.com/rjsf-team/react-jsonschema-form/pull/1395)) +- Fix id of oneof and anyof select ([#1212](https://github.com/rjsf-team/react-jsonschema-form/pull/1212)). The oneof select id is now suffixed by \_\_oneof_select and the anyof select by \_\_anyof_select. +- React 16+ is now a peer dependency ([#1408](https://github.com/rjsf-team/react-jsonschema-form/pull/1408)) +- We no longer actively support Node version < 8 ([#1462](https://github.com/rjsf-team/react-jsonschema-form/pull/1462)) +- Removed setState, setImmediate, safeRenderCompletion helpers/hacks ([#1454](https://github.com/rjsf-team/react-jsonschema-form/pull/1454), [#1720](https://github.com/rjsf-team/react-jsonschema-form/pull/1720)) +- Inject defaults in arrays ([#1499](https://github.com/rjsf-team/react-jsonschema-form/pull/1499)) + +### Features + +- Add material-ui theme in the main repo ([#1420](https://github.com/rjsf-team/react-jsonschema-form/pull/1420)) (note: has not been fully integrated yet -- this will be fully integrated when we publish multiple packages with lerna - [#1501](https://github.com/rjsf-team/react-jsonschema-form/pull/1501)) +- Add extraErrors prop for async validation ([#1444](https://github.com/rjsf-team/react-jsonschema-form/pull/1444)) +- Add support for overriding UnsupportedField ([#1660](https://github.com/rjsf-team/react-jsonschema-form/pull/1660)) + +### Fixes + +- Fix issue with false as formData on radio components ([#1438](https://github.com/rjsf-team/react-jsonschema-form/pull/1438)) +- Security patches ([#1458](https://github.com/rjsf-team/react-jsonschema-form/pull/1458), [#1459](https://github.com/rjsf-team/react-jsonschema-form/pull/1459)) +- Memo components in custom widgets and fields. ([#1447](https://github.com/rjsf-team/react-jsonschema-form/pull/1447)) +- Introduce Form autoComplete attribute and deprecate autocomplete ([#1483](https://github.com/rjsf-team/react-jsonschema-form/pull/1483)) +- Rewrite mergeSchemas to fix schema dependencies merging ([#1476](https://github.com/rjsf-team/react-jsonschema-form/pull/1476)) +- Update arrays correctly when changing index ([#1485](https://github.com/rjsf-team/react-jsonschema-form/pull/1485)) +- Update anyOf schema to correctly update items in an array ([#1491](https://github.com/rjsf-team/react-jsonschema-form/pull/1491)) +- Update schema to re-render when idschema changes ([#1493](https://github.com/rjsf-team/react-jsonschema-form/pull/1493)) +- Make sure BooleanField supports an overridable DescriptionField ([#1594](https://github.com/rjsf-team/react-jsonschema-form/pull/1594)) +- Export typings ([#1607](https://github.com/rjsf-team/react-jsonschema-form/pull/1607)) diff --git a/packages/docs/versioned_docs/version-5.24.10/migration-guides/v3.x upgrade guide.md b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v3.x upgrade guide.md new file mode 100644 index 0000000000..963eb195d0 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v3.x upgrade guide.md @@ -0,0 +1,29 @@ +# 3.x Upgrade Guide + +## Breaking changes + +### Node support + +Dropped support for Node 8, 9, 10. Minimum supported version of Node.js is now 12. + +### Dereferenced schemas for `anyOf`/`allOf` options + +`MultiSchemaField`'s `options` interface is different. Before, an option could include a `$ref`. Now, any option with a reference will be resolved/dereferenced when given as props for `MultiSchemaField`. + +### Help field IDs + +IDs for [Help fields](../api-reference/uiSchema.md#help) are now suffixed by `__help` so that the IDs are unique. Previously, their IDs would be nonexistent or the same as the fields that they were describing. + +### Bring your own polyfills + +core-js@2 has been removed from @rjsf/core. See more about [the rationale here](https://github.com/rjsf-team/react-jsonschema-form/pull/2211#issue-563700810). + +If you're using a framework like [Create React App](https://create-react-app.dev/docs/supported-browsers-features#supported-browsers), [Gatsby](https://www.gatsbyjs.com/docs/how-to/custom-configuration/browser-support/), [Next.js](https://nextjs.org/docs/basic-features/supported-browsers-features), or transpiling code through something like `@babel/preset-env`, polyfills are already included there and you won't have to do anything. + +If you were directly depending on @rjsf/core's @babel/runtime pulling in core-js@2, just `npm install core-js` and using a side effectful import at the top of your entry point (`import 'core-js'`) might be enough. + +For a slightly more elaborate setup, [@babel/preset-env](https://babeljs.io/docs/en/babel-preset-env#how-does-it-work) is probably a good second choice. + +From `@babel/preset-env`'s docs + +> We leverage [`browserslist`, `compat-table`, and `electron-to-chromium`] to maintain mappings of which version of our supported target environments gained support of a JavaScript syntax or browser feature, as well as a mapping of those syntaxes and features to Babel transform plugins and core-js polyfills. diff --git a/packages/docs/versioned_docs/version-5.24.10/migration-guides/v4.x upgrade guide.md b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v4.x upgrade guide.md new file mode 100644 index 0000000000..431b7bd0cf --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v4.x upgrade guide.md @@ -0,0 +1,11 @@ +# 4.x Upgrade Guide + +## Breaking changes + +### React version + +No longer actively supporting React version < 16.3. The minimum supported version of React is now 16.3. [Discussion can be found here](https://github.com/rjsf-team/react-jsonschema-form/pull/2605#discussion_r792685354) + +### @rjsf/material-ui package - Minimum version of material-ui 4 + +If you are using the material-ui 4 theme, @material-ui/core and @material-ui/icons packages should be updated to the latest versions. The minimum versions supported for @material-ui/core and @material-ui/icons are 4.12.0 and 4.11.1 respectively. This change is required for [support for the material-ui version 5 theme](https://github.com/rjsf-team/react-jsonschema-form/tree/main/packages/material-ui) diff --git a/packages/docs/versioned_docs/version-5.24.10/migration-guides/v5.x upgrade guide.md b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v5.x upgrade guide.md new file mode 100644 index 0000000000..edc19c46e8 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/migration-guides/v5.x upgrade guide.md @@ -0,0 +1,572 @@ +# 5.x Upgrade Guide + +## Breaking changes + +There were several significant **breaking changes** in RJSF version 5 that were necessary in order to support the following new features: + +- Schema validation was decoupled from `@rjsf/core` to resolve issue [#2693](https://github.com/rjsf-team/react-jsonschema-form/issues/2693). Additionally, in order to break a circular dependency in the validation refactor, the `@rjsf/core/utils.js` file was split out into its own `@rjsf/utils` package as was suggested in [#1655](https://github.com/rjsf-team/react-jsonschema-form/issues/1655). +- The theme for Material UI version 5 (i.e. `@rjsf/mui`) was split out of the theme for version 4 (i.e. `@rjsf/material-ui`) to resolve the following issues: [#2762](https://github.com/rjsf-team/react-jsonschema-form/issues/2762), [#2858](https://github.com/rjsf-team/react-jsonschema-form/issues/2858), [#2905](https://github.com/rjsf-team/react-jsonschema-form/issues/2905), [#2945](https://github.com/rjsf-team/react-jsonschema-form/issues/2945) +- As part of the fix for [#2526](https://github.com/rjsf-team/react-jsonschema-form/issues/2526) all the existing templates in the previous version were moved into a new `templates` dictionary, similar to how `widgets` and `fields` work. This `templates` dictionary was added to the `Registry` and also the `Form` props, replacing the `ArrayFieldTemplate`, `FieldTemplate`, `ObjectFieldTemplate` and `ErrorList` props. In addition, several of the `fields` and `widgets` based components were moved into the `templates` dictionary as they were more like templates than true `Field`s or `Widget`s. Also fixes [#2945](https://github.com/rjsf-team/react-jsonschema-form/issues/2945) +- Fixed `anyOf` and `oneOf` getting incorrect, potentially duplicate ids when combined with array [#2197](https://github.com/rjsf-team/react-jsonschema-form/issues/2197) +- `CheckboxesWidget`, `RadioWidget` and `SelectWidget` in all themes now use indexes into `enumOptions[]` rather than `option.value` to allow for objects in `enumOptions` - [#1494](https://github.com/rjsf-team/react-jsonschema-form/issues/1494) + +### Node support + +Version 5 is dropping official support for Node 12 as it is no longer a [maintained version](https://nodejs.org/en/about/releases/). +Please use Node 18 when making any changes to `package.json` and `package-lock.json` files. +All PR and branch builds are running against Node 14, 16 and 18. + +### React version + +RJSF is no longer actively supporting React version < 16.14.x. +React 17 is officially supported on all the themes where the underlying theme library also supports React 17. + +Unfortunately, there is required work pending to properly support React 18, so use it at your own risk. + +### New packages + +There are four new packages added in RJSF version 5: + +- `@rjsf/utils`: All of the [utility functions](../api-reference/utility-functions.md) previously imported from `@rjsf/core/utils` as well as the Typescript types for RJSF version 5. + - The following new utility functions were added: `ariaDescribedByIds()`, `createSchemaUtils()`, `descriptionId()`, `enumOptionsDeselectValue()`, `enumOptionsIndexForValue()`, `enumOptionsIsSelected()`, `enumOptionsSelectValue()`, `enumOptionsValueForIndex()`, `errorId()`, `examplesId()`, `getClosestMatchingOption()`, `getFirstMatchingOption()`, `getInputProps()`, `helpId()`, `mergeValidationData()`, `optionId()`, `sanitizeDataForNewSchema()` and `titleId()` +- `@rjsf/validator-ajv6`: The [ajv](https://github.com/ajv-validator/ajv)-v6-based validator refactored out of `@rjsf/core@4.x`, that implements the `ValidatorType` interface defined in `@rjsf/utils`. +- `@rjsf/validator-ajv8`: The [ajv](https://github.com/ajv-validator/ajv)-v8-based validator that is an upgrade of the `@rjsf/validator-ajv6`, that implements the `ValidatorType` interface defined in `@rjsf/utils`. See the ajv 6 to 8 [migration guide](https://ajv.js.org/v6-to-v8-migration.html) for more information. +- `@rjsf/mui`: Previously `@rjsf/material-ui/v5`, now provided as its own theme. + +### `id` BREAKING CHANGES + +In many of the themes the `id`s for the `Title`, `Description` and `Examples` blocks were update to all have a consistent value of `xxx__title`, `xxx__description` and `xxx__examples`, respectively, where `xxx` is the id of the field. +In addition, some of the `id`s for various input values were updated to be consistent across themes or to fix small bugs. +For instance, the values for radio buttons in the `RadioWidget` and checkboxes in the `CheckboxesWidget` are of the form `xxx-${option.value}`, where `xxx` is the id of the field. + +### `enumOptions[]` widgets BREAKING CHANGES + +Schemas may have `enumOptions[]` where values are objects rather than primitive types. Examples of such schemas have been added to the playground. These schemas did not work in RJSF prior to v5. +In every theme, the `enumOptions[]` rendering widgets `CheckboxesWidget`, `RadioWidget` and `SelectWidget` previously used the `enumOptions[].value` to as the value used for the underlying `checkbox`, `radio` and `select.option` elements. +Now, these `CheckboxesWidget`, `RadioWidget` and `SelectWidget` components use the index of the `enumOptions[]` in the list as the value for the underlying elements. +If you need to build a custom widget for this kind of `enumOptions`, there are a set of `enumOptionsXXX` functions in `@rjsf/utils` to support your implementation. + +### `@rjsf/core` BREAKING CHANGES + +#### Types + +In version 4, RJSF exported all its types directly from `@rjsf/core`. +In version 5, only the types for the `Form` component and the `withTheme()` HOC are exported directly from `@rjsf/core`. +All the rest of the types for RJSF are now exported from the new `@rjsf/utils` package. + +NOTE: The types in `@rjsf/utils` have been improved significantly from those in version 4 and as a result may require you to fix your Typescript typings and add some casts. + +Some of the most notable changes are: + +- `RJSFSchema` has replaced the use of `JSON7Schema` for future compatibility reasons. + - Currently `RJSFSchema` is simply an alias to `JSON7Schema` so this change is purely a naming one. + - It is highly recommended to update your use of `JSON7Schema` with `RJSFSchema` so that when the RJSF begins supporting a newer JSON Schema version out-of-the-box, your code won't be affected. +- `RJSFSchemaDefinition` has replaced the use of `JSONSchema7Definition` for the same reasons. + +- The use of the generic `T` (defaulting to `any`) for the `formData` type has been expanded to cover all type hierarchies that use `formData`. +- `StrictRJSFSchema` and `RJSFSchema` have replaced the use of `JSON7Schema` for future compatibility reasons. + - `RJSFSchema` is `StrictRJSFSchema` joined with the `GenericObjectType` (i.e. `{ [key: string]: any }`) to allow for additional syntax related to newer draft versions + - All definitions of `schema` and `rootSchema` elements have been replaced with a generic that is defined as `S extends StrictRJSFSchema = RJSFSchema` + - It is highly recommended to update your use of `JSON7Schema` with `RJSFSchema` since that is the default for the new generic used for `schema` and `rootSchema` +- A new generic `F` (extending `FormContextType` defaulting to `any`) was added for the `formContext` type, and all types in the hierarchy that use `formContext` have had that generic added to them. +- The new `CustomValidator`, `ErrorTransformer`, `ValidationData`, `ValidatorType` and `SchemaUtilsType` types were added to support the decoupling of the validation implementation. +- The new `TemplatesType`, `ArrayFieldDescriptionProps`, `ArrayFieldTitleProps`, `UnsupportedFieldProps`, `IconButtonProps`, `SubmitButtonProps` and `UIOptionsBaseType` were added to support the consolidation (and expansion) of `templates` in the `Registry` and `Form`. +- **BREAKING CHANGE** The `DescriptionField` and `TitleField` props were removed from the `ArrayFieldTemplateProps` and `ObjectFieldTemplateProps` as they can now be derived from the `templates` or `uiSchema` via the new `getTemplate()` utility function. +- **BREAKING CHANGE** The `fields` prop was removed from the `FieldTemplateProps` as you can simply use `registry.fields` instead. +- **BREAKING CHANGE** The `showErrorList` prop was changed to accept `false`, `"top"` or `"bottom"`. `true` is no longer a valid value. The default value is `"top"`, which has identical behavior to the default value/`true` in v4. + You can view all these [types](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/utils/src/types.ts) on GitHub. + +#### Form props + +In version 5, the `Form` component's two optional props `additionalMetaSchemas` and `customFormats` were replaced with the new, required `validator` prop, in order to support the decoupling of the validation implementation. +This new `validator` prop is expected to be an implementation of the `ValidatorType` interface. +The new `@rjsf/validator-ajv6` package contains the refactored implementation of the version 4 validator; It was provided for backwards compatibility with RJSF v4, and it is deprecated. +The new `@rjsf/validator-ajv8` package contains the refactored implementation of the version 4 validator, that has been converted to use the `Ajv 8` validator and has more capabilities than the `Ajv 6` one. See the [Ajv migration guide](https://ajv.js.org/v6-to-v8-migration.html) for more information. + +There are two ways to use this new package to provide a `validator` for a `Form`. +First, you can simply import the default validator from the package and pass it to a `Form`. + +```tsx +import { RJSFSchema } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv8"; + +// Your schema +const schema: RJSFSchema = { ... }; + +render(( + +), document.getElementById("app")); +``` + +Second, if you were actually providing one (or both) of the removed optional props to your `Form`, you can continue using them by creating a customized validator. + +```tsx +import { RJSFSchema } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import { customizeValidator, CustomValidatorOptionsType } from "@rjsf/validator-ajv8"; + +// Your schema, additionalMetaSchemas and/or customFormats +const schema: RJSFSchema = { ... }; +const additionalMetaSchemas: CustomValidatorOptionsType['additionalMetaSchemas'] = [{ ... }]; +const customFormats: CustomValidatorOptionsType['customFormats'] = { ... }; + +const validator = customizeValidator({ additionalMetaSchemas, customFormats }); + +render(( + +), document.getElementById("app")); +``` + +##### `formElement` converted to RefObject + +The `formElement` variable that stored the ref to the inner `` was converted from a simple variable assigned via a [callback ref](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) (ala React < 16.3) to a React.RefObject created using the `React.createRef()` API. +As a result, if you were using the `formElement` ref, you will need to update it to use `formElement.current`: + +```tsx +import { RJSFSchema } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv8"; + +// Your schema +const schema: RJSFSchema = { ... }; + +const formRef = React.createRef(); + +render(( + +), document.getElementById("app")); + +... +// Previously, to reset the form one would have called: +// formRef.current.formElement.reset(); +// Now one calls: +formRef.current.formElement.current.reset(); +``` + +##### `validate` prop renamed + +Additionally, in version 5, the `validate` prop on `Form` was renamed to `customValidate` to avoid confusion with the new `validator` prop. + +##### `fields` prop changes + +In previous versions, it was possible to provide an override to the `DescriptionField`, `TitleField` and/or `UnsupportedField` components by providing a custom implementation in the `fields` prop on the `Form`. +Since these components do not actually support the `FieldProps` interface, they were moved into the `templates` dictionary instead. +If you were previously overriding any (or all) of these components, you can override them now via the `templates` prop on `Form` instead: + +```tsx +import { DescriptionFieldProps, RJSFSchema, TitleFieldProps } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv8"; + +// Your schema +const schema: RJSFSchema = { ... }; + +// Your custom fields +const CustomDescriptionField = (props: DescriptionFieldProps) => { ... }; +const CustomTitleField = (props: TitleFieldProps) => { ... }; +const CustomUnsupportedField = (props: ObjectFieldTemplateProps) => { ... +}; + +const templates: Partial = { + DescriptionFieldTemplate: CustomDescriptionField, + TitleFieldTemplate: CustomTitleField, + UnsupportedFieldTemplate: CustomUnsupportedField, +}; + +render(( + +), document.getElementById("app")); +``` + +##### new `templates` prop + +Additionally, in version 5, the `ArrayFieldTemplate`, `FieldTemplate`, `ObjectFieldTemplate` and `ErrorList` props were replaced with the `templates` prop as part of the `TemplatesType` consolidation. +If you were previously overriding any (or all) of these templates, you can simply consolidate them into the new `templates` prop on `Form` instead: + +```tsx +import { ArrayFieldTemplateProps, ErrorListProps, FieldTemplateProps, ObjectFieldTemplateProps, RJSFSchema } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv8"; + +// Your schema +const schema: RJSFSchema = { ... }; + +// Your custom templates +const CustomArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { ... }; +const CustomFieldTemplate = (props: FieldTemplateProps) => { ... }; +const CustomObjectFieldTemplate = (props: ObjectFieldTemplateProps) => { ... }; +const CustomErrorField = (props: ErrorListProps) => { ... }; + +const templates: Partial = { + ArrayFieldTemplate: CustomArrayFieldTemplate, + FieldTemplate: CustomFieldTemplate, + ObjectFieldTemplate: CustomObjectFieldTemplate, + ErrorFieldTemplate: CustomErrorField, +}; + +render(( + +), document.getElementById("app")); +``` + +NOTE: In version 5, the `ArrayField` implementation was refactored to add 3 additional templates for presenting arrays along with the `ArrayFieldTemplate`. +If you were updating the `ArrayFieldTemplate` to modify just a subset of the UI, it may be easier for you to implement one of the other new templates instead. +See the [Custom Templates](../advanced-customization/custom-templates.md) documentation for more details. + +##### `widgets` prop change + +In the previous version, it was possible to provide an override to the `SubmitButton` component by providing a custom implementation in the `widgets` prop on the `Form`. +Since this component only requires a tiny fraction of the `WidgetProps` interface, it was moved into the `templates.ButtonTemplates` dictionary instead with its own, reduced set of props. +If you were previously overriding this component, you can override it now via the `templates` prop on `Form` instead: + +```tsx +import { RJSFSchema, SubmitButtonProps } from "@rjsf/utils"; +import Form from "@rjsf/core"; +import validator from "@rjsf/validator-ajv8"; + +// Your schema +const schema: RJSFSchema = { ... }; + +// Your custom button +const CustomSubmitButton = (props: SubmitButtonProps) => { ... +}; + +const templates: Partial = { + ButtonTemplates: { + SubmitButton: CustomSubmitButton, + } +}; + +render(( + +), document.getElementById("app")); +``` + +#### utils.js + +In version 5, all the utility functions that were previously accessed via `import { utils } from '@rjsf/core';` are now available via `import utils from '@rjsf/utils';`. +Because of the decoupling of validation from `@rjsf/core` there is a breaking change for all the [validator-based utility functions](../api-reference/utility-functions.md#validator-based-utility-functions), since they now require an additional `ValidatorType` parameter. +More over, one previously exported function `resolveSchema()` is no longer exposed in the `@rjsf/utils`, so use `retrieveSchema()` instead. +Finally, the function `getMatchingOption()` has been deprecated in favor of `getFirstMatchingOption()`. + +If you have built custom fields or widgets that utilized any of these breaking-change functions, don't worry, there is a quick and easy solution for you. +The `registry` has a breaking-change which removes the previously deprecated `definitions` property while adding the new `schemaUtils` property. +This new `registry.schemaUtils` property implements the `SchemaUtilsType` interface, which allows you to call a version of each of these breaking-change functions without the need for passing either a `validator` or `rootSchema`. +Because all fields and widgets are guaranteed to be passed the `registry` as a prop, if your custom field/widget happens to use either the `registry.definitions` object or a breaking-change validator-based utility function you make the following changes: + +```tsx +import { RJSFSchema, FieldProps } from '@rjsf/utils'; + +function YourField(props: FieldProps) { + const { registry } = props; +// Change `registry.definitions` to `registry.rootSchema.definitions` +// const { definitions } = registry; <- version 4 + const { rootSchema } = registry; + const { definitions } = rootSchema; +... +} +``` + +```tsx +// Change breaking-change function to schemaUtils instead, otherwise import from @rjsf/utils +// import { utils } from '@rjsf/core'; <- version 4 +// const { isMultiSelect, resolveSchema, getUiOptions } = utils; <- version 4 +import { RJSFSchema, WidgetProps, getUiOptions } from '@rjsf/utils'; + +function YourWidget(props: WidgetProps) { + const { registry, uiSchema } = props; + const { schemaUtils } = registry; +// const matchingOption = getMatchingOption({}, options, rootSchema); <- version 4 +// const isMultiSelect = isMultiSelect(schema, rootSchema); <- version 4 +// const newSchema = resolveSchema(schema, formData, rootSchema); <- version 4 + const matchingOption = schemaUtils.getFirstMatchingOption({}, options); + const isMultiSelect = schemaUtils.isMultiSelect(schema); + const newSchema: RJSFSchema = schemaUtils.retrieveSchema(schema, formData); + const options = getUiOptions(uiSchema); + +... +} +``` + +#### validator.js + +Because of the decoupling of validation from `@rjsf/core` this file was refactored into its own `@rjsf/validator-ajv8` package. +During that refactor a few **breaking changes** were made to how it works related to custom validation and `ErrorSchema` conversion. + +##### toErrorList param changed + +In previous versions, the `toErrorList()` function used to take a `fieldName` string defaulted to `root`, and used it to format the `stack` message. +In version 5, `fieldName` was changed to `fieldPath` string array defaulted to an empty array, and is used to recursively add the field name to the errors as the `property` object along with the raw `message`. +The result is that if you had an `ErrorSchema` that looks like: + +```tsx +const errorSchema: ErrorSchema = { + __errors: ['error message 1'], + password: { __errors: 'passwords do not match' }, +}; +``` + +The returned result from calling `toErrorList(errorSchema)` has changed as follows: + +```tsx +// version 4 result +[{ stack: 'root: error message 1' }, { stack: 'password: passwords do not match' }][ + // version 5 result + ({ property: '.', message: 'error message 1', stack: '. error message 1' }, + { + property: '.password', + message: 'passwords do not match', + stack: '.password passwords do not match', + }) +]; +``` + +##### Custom validation and extraErrors + +In previous versions, when using a custom validator on the `Form`, any errors that were generated were inconsistently inserted into the validations `errors` list. +In addition, there was an [issue](https://github.com/rjsf-team/react-jsonschema-form/issues/1596) where the non-`stack` AJV error information was lost when custom validation generated errors. +This issue has been fixed. +Also, when `extraErrors` were provided, they were being inconsistently inserted into the `errors` list and the non-`stack` AJV error information was lost. +In version 5, all of these errors will be consistently appended onto the end of the validation `errors` list, and the additional AJV error information is maintained. + +In other words, if custom validation or `extraErrors` produced the following `ErrorSchema`: + +```tsx +{ + __errors: [ "Please correct your password"], + password2: { __errors: "passwords do not match" } +} +``` + +And the AJV validation produced the following `ErrorSchema`: + +```tsx +{ + __errors: [ + { + message: 'should NOT be shorter than 3 characters', + name: 'minLength', + params: { limit: 3 }, + property: '.password2', + schemaPath: '#/properties/password2/minLength', + stack: '.password2 should NOT be shorter than 3 characters', + }, + ]; +} +``` + +The resulting `errors` list has changed as follows: + +```tsx +// version 4 +[ + { stack: 'root: Please correct your password' }, + { stack: 'password2: passwords do not match' }, + { stack: 'password2: should NOT be shorter than 3 characters' }, +][ + // version 5 + ({ + message: 'should NOT be shorter than 3 characters', + name: 'minLength', + params: { limit: 3 }, + property: '.password2', + schemaPath: '#/properties/password2/minLength', + stack: '.password2 should NOT be shorter than 3 characters', + }, + { + property: '.', + message: 'Please correct your password', + stack: '. Please correct your password', + }, + { + property: '.', + message: 'passwords do not match', + stack: '.password2 passwords do not match', + }) +]; +``` + +#### Generate correct ids when arrays are combined with `anyOf`/`oneOf` + +In v4, with arrays inside `anyOf` or `oneOf`, the parent name was not used to generate ids. +For example, given a schema such as: + +```json +{ + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "anyOf": [ + { + "properties": { + "foo": { + "type": "string" + } + } + }, + { + "properties": { + "bar": { + "type": "string" + } + } + } + ] + } + } + } +} +``` + +We would get fields with id `root_foo` and `root_bar`. +As you can imagine, we could end up with duplicated ids if there's actually a `foo` or a `bar` in the root of the schema. + +From v5, the child fields will correctly use the parent id when generating its own id, generating ids such as `root_items_0_foo`. + +#### Deprecations added in v5 + +##### getMatchingOption() + +The utility function `getMatchingOption()` was deprecated in favor of the more aptly named `getFirstMatchingOption()` which has the exact same implementation. + +##### Non-standard `enumNames` property + +`enumNames` is a non-standard JSON Schema field that was deprecated in version 5. +`enumNames` could be included in the schema to apply labels that differed from an enumeration value. +This behavior can still be accomplished with `oneOf` or `anyOf` containing `const` values, so `enumNames` support will be removed from a future major version of RJSF. +For more information, see [#532](https://github.com/rjsf-team/react-jsonschema-form/issues/532). + +##### uiSchema.classNames + +In versions previous to 5, `uiSchema.classNames` was the only property that did not require the `ui:` prefix. +Additionally, it did not support being added into the `ui:options` object. +This was fixed in version 5 to be consistent with all the other properties in the `uiSchema`, so the `uiSchema.classNames` support may be removed from a future major version of RJSF. + +If you are using `classNames` as follows, simply add the `ui:` prefix to it to remove the deprecation warning that will be displayed for each `uiSchema.classNames` you have: + +```tsx +import { UiSchema } from '@rjsf/utils'; + +// This uiSchema will log a deprecation warning to the console +const uiSchemaLog: UiSchema = { + title: { + classNames: 'myClass', + }, +}; +// This uiSchema will not +const uiSchemaNoLog: UiSchema = { + title: { + 'ui:classNames': 'myClass', + }, +}; +``` + +### `@rjsf/material-ui` BREAKING CHANGES + +This theme was simplified back to working only with Material UI version 4 after an unsuccessful attempt to have it fully support both versions 4 and 5 simultaneously. +As a result, the `MuiComponentContext`, `MuiForm5`, `Theme5` components and the `useMuiComponent` hook were removed from the export. +In addition, the `/v4` and `/v5` sub-packages were also removed. + +#### Migrating for Material UI version 4 + +If you were using this theme for Material UI version 4 AND you were using the sub-package, simply remove the `/v4` from your imports. + +If you modified your Typescript configuration for the `/v4` sub-package, remove the following from your `tsconfig.json`: + +``` +{ + ... + "compilerOptions": { + ... + "baseUrl": ".", + "paths": { + "@rjsf/material-ui/*": ["node_modules/@rjsf/material-ui/dist/*"] + } + } +} +``` + +If you modified your Jest configuration for the `/v4` sub-package, remove the following from your `jest.config.json`: + +``` + "moduleNameMapper": { + "@rjsf/material-ui/v4": "/node_modules/@rjsf/material-ui/dist/v4.js" + }, +``` + +#### Migrating for Material UI version 5 + +If you were using this theme for Material UI version 5, you will want to use `@rjsf/mui` instead. +See below for some before and after examples. + +If you modified your Typescript configuration for the `/v5` sub-package, remove the following from your `tsconfig.json`: + +``` +{ + ... + "compilerOptions": { + ... + "baseUrl": ".", + "paths": { + "@rjsf/material-ui/*": ["node_modules/@rjsf/material-ui/dist/*"] + } + } +} +``` + +If you modified your Jest configuration for the `/v5` sub-package, remove the following from your `jest.config.json`: + +``` + "moduleNameMapper": { + "@rjsf/material-ui/v5": "/node_modules/@rjsf/material-ui/dist/v5.js" + }, +``` + +##### Before + +```tsx +import Form5 from '@rjsf/material-ui'; +``` + +or + +```tsx +import Form from '@rjsf/material-ui/v5'; +``` + +or + +```tsx +import { withTheme } from '@rjsf/core'; +import { Theme } from '@rjsf/material-ui/v5'; +// Make modifications to the theme with your own fields and widgets +const Form = withTheme(Theme); +``` + +or + +```tsx +import { withTheme } from '@rjsf/core'; +import { Theme as Theme5 } from '@rjsf/material-ui'; +// Make modifications to the theme with your own fields and widgets +const Form = withTheme(Theme5); +``` + +##### After + +```tsx +import Form from '@rjsf/mui'; +``` + +or + +```tsx +import { withTheme } from '@rjsf/core'; +import { Theme } from '@rjsf/mui'; +// Make modifications to the theme with your own fields and widgets +const Form = withTheme(Theme); +``` diff --git a/packages/docs/versioned_docs/version-5.24.10/usage/index.mdx b/packages/docs/versioned_docs/version-5.24.10/usage/index.mdx new file mode 100644 index 0000000000..b005791b6c --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/usage/index.mdx @@ -0,0 +1,11 @@ +--- +title: Usage and Customization +description: How to use react-jsonschema-form and customize your form behavior and appearance. + +--- + +import DocCardList from '@theme/DocCardList'; + +

{frontMatter.description}

+ + \ No newline at end of file diff --git a/packages/docs/versioned_docs/version-5.24.10/usage/themes.md b/packages/docs/versioned_docs/version-5.24.10/usage/themes.md new file mode 100644 index 0000000000..779d742401 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/usage/themes.md @@ -0,0 +1,49 @@ +# Themes + +By default, this library renders form fields and widgets leveraging the [Bootstrap](http://getbootstrap.com/) semantics, +meaning that you must load the Bootstrap stylesheet on the page to view the form properly. You can use another theme by importing one of the packages listed below. + +## Supported themes + +| Theme Name | Status | Package Name / Link | +| --------------------- | --------- | ------------------- | +| antd | Published | `@rjsf/antd` | +| Bootstrap 3 (default) | Published | `@rjsf/core` | +| Bootstrap 4 | Published | `@rjsf/bootstrap-4` | +| Chakra UI | Published | `@rjsf/chakra-ui` | +| fluent-ui | Published | `@rjsf/fluent-ui` | +| fluentui-rc | Published | `@rjsf/fluentui-rc` | +| material-ui 4 | Published | `@rjsf/material-ui` | +| material-ui 5 | Published | `@rjsf/mui` | +| Semantic UI | Published | `@rjsf/semantic-ui` | + +## Using themes + +To use a theme from a package, just import the `` component from that package. For example, to use the material ui form, +first install both `@rjsf/core` and `@rjsf/material-ui`. Then you can import the form by doing: + +```ts +import Form from '@rjsf/material-ui'; +``` + +If you would like to contribute a theme with a new UI framework, please develop the theme using the `withTheme` component described in [Theme Customization](../advanced-customization/custom-themes.md) and make a PR! + +You can also use the uiSchema to add custom CSS class names to your form. + +## Customizing with other frameworks + +The default theme is bootstrap 3. In order to use another theme, you must first install `@rjsf/core`. + +For example, to use the standard bootstrap 3 form, you can run: + +```ts +import Form from '@rjsf/core'; +``` + +To use the material-ui 5 form, you should first install both `@rjsf/core` and `@rjsf/mui`. Then, you can run: + +```ts +import Form from '@rjsf/mui'; +``` + +For more information on how to create a custom theme, see documentation on the `withTheme` component. diff --git a/packages/docs/versioned_docs/version-5.24.10/usage/validation.md b/packages/docs/versioned_docs/version-5.24.10/usage/validation.md new file mode 100644 index 0000000000..00674a7e43 --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/usage/validation.md @@ -0,0 +1,799 @@ +# Validation + +When the form is submitted, the form data is validated to conform to the given JSON schema; + +As of version 5, as a result of decoupling the validation implementation from the `Form`, a `validator` implementation is required to be passed to all `Form`s. +React Json Schema Form provides a default `@rjsf/validator-ajv6` implementation that uses version 6 of the [ajv](https://github.com/ajv-validator/ajv) validator. + +> NOTE: The ajv6 validator has been deprecated from the outset in favor of the `@rjsf/validator-ajv8` and is provided primarily to assist in code migrations + +It also provides a new `@rjsf/validator-ajv8` implementation that uses version 8 of the [ajv](https://github.com/ajv-validator/ajv) validator. +The error messages generated by this new validator differ from those provided by the original validator due to it using a newer version. +If you depend on having specifically formatted messages, then using this validator would constitute a breaking change for you. + +It is also possible for you to provide your own implementation if you desire, as long as it fulfills the `ValidatorType` interface specified in `@rjsf/utils`. + +## API documentation + +The documentation for the APIs associated with the AJV 8 validator package can be found [here](../api-reference/validator-ajv8.md) + +## Precompiled validators + +In 5.7.0, support for precompiled validators was added to the `@rjsf/validator-ajv8` package. +The main use case for this is to overcome issues with `unsafe-eval` warnings from the browser caused by strict Content Security Policy settings. +See the [Standalone Validation Code](https://ajv.js.org/standalone.html) section of the AJV documentation for more details about precompiled validators. + +Due to how RJSF uses the AJV validator in determining `anyOf/oneOf` selections and how it resolves dependencies, if-then-else and references ($ref) in schemas via the `retrieveSchema()` utility method, RJSF provides its own schema compilation API built on-top-of the one provided by AJV 8. +If you are wanting to use a precompiled validator, two steps are required: + +1. Precompiling the schema into a set of validator functions +2. Providing those precompiled validator functions to a `ValidatorType` implementation in the `Form` + +### Schema precompilation + +The first step in the process is to compile a schema into a set of validator functions that are saved into a commonJS-based Javascript file. +The `@rjsf/validator-ajv8` package exports the `compileSchemaValidators()` function that does this. +It is expected that this function will be used in a manner similar to the following: + +```cjs +const compileSchemaValidators = require('@rjsf/validator-ajv8/dist/compileSchemaValidators').default; +const yourSchema = require('path_to/yourSchema'); // If your schema is a js file + +compileSchemaValidators(yourSchema, 'path_to/yourCompiledSchema.js'); +``` + +If you are currently using the `customizeValidator()` function to provide `additionalMetaSchemas`, `customFormats`, `ajvOptionsOverrides` and/or `ajvFormatOptions` then you can pass those in as the optional third parameter to the `compileSchemaValidators()` function in a manner similar to: + +```cjs +const { compileSchemaValidators } = require('@rjsf/validator-ajv8'); +const yourSchema = require('path_to/yourSchema.json'); // If your schema is a json file + +const options = { + additionalMetaSchemas: [require('ajv/lib/refs/json-schema-draft-06.json')], + customFormats: { 'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/, 'area-code': /\d{3}/ }, + ajvOptionsOverrides: { + $data: true, + verbose: true, + }, + ajvFormatOptions: { + mode: 'fast', + }, +}; + +compileSchemaValidators(yourSchema, 'path_to/yourCompiledSchema.js', options); +``` + +It is highly recommended to create a `compileYourSchema.js` file (or what ever name you want) with code similar to what is shown above and then, using node, run the code as follows: + +``` +node compileYourSchema.js +``` + +> NOTE: You must have your schema provided within a file that can be parsed and turned into the set of precompiled validator functions. + +> Additional Note: If you are using Webpack or NextJS and are encountering an issue resolving `fs` during development, consult this [blog post](https://bobbyhadz.com/blog/module-not-found-cant-resolve-fs) for how to solve the issue. + +### Using the precompiled validator + +After you have completed step 1 having generated your precompiled schema functions into the `yourCompiledSchema.js` output file (or whatever you called it), then you need to create a `ValidatorType` implementation from it to use in the `Form`. +The `@rjsf/validator-ajv8` package exports the `createPrecompiledValidator()` function for this. +Here is an example of how to use your precompiled validator with your `Form`: + +```tsx +import { createPrecompiledValidator, ValidatorFunctions } from '@rjsf/validator-ajv8'; +import Form from '@rjsf/core'; // Or whatever theme you use + +import yourSchema from 'path_to/yourSchema'; // This needs to be the same file that was precompiled +import * as precompiledValidator from 'path_to/yourCompiledSchema'; + +const validator = createPrecompiledValidator(precompiledValidator as ValidatorFunctions); + +render(, document.getElementById('app')); +``` + +### Dynamically pre-compiling validators + +For more advanced cases when schema needs to be precompiled on request - `compileSchemaValidatorsCode` can be used. + +```ts +import { compileSchemaValidatorsCode } from '@rjsf/validator-ajv8/dist/compileSchemaValidators'; + +const code = compileSchemaValidatorsCode(schema, options); +``` + +For the most part it is the same as `compileSchemaValidators`, but instead of writing the file - it returns generated code directly. + +To use it on browser side - some modifications are needed to provide runtime dependencies in generated code needs to be provided. + +Example implementation of it: + +```tsx +import type { ValidatorFunctions } from '@rjsf/validator-ajv8'; + +import ajvRuntimeEqual from 'ajv/dist/runtime/equal'; +import { + parseJson as ajvRuntimeparseJson, + parseJsonNumber as ajvRuntimeparseJsonNumber, + parseJsonString as ajvRuntimeparseJsonString, +} from 'ajv/dist/runtime/parseJson'; +import ajvRuntimeQuote from 'ajv/dist/runtime/quote'; +// import ajvRuntimeRe2 from 'ajv/dist/runtime/re2'; +import ajvRuntimeTimestamp from 'ajv/dist/runtime/timestamp'; +import ajvRuntimeUcs2length from 'ajv/dist/runtime/ucs2length'; +import ajvRuntimeUri from 'ajv/dist/runtime/uri'; +import * as ajvFormats from 'ajv-formats/dist/formats'; + +// dependencies to replace in generated code, to be provided by at runtime +const validatorsBundleReplacements: Record = { + // '': ['', ], + 'require("ajv/dist/runtime/equal").default': ['ajvRuntimeEqual', ajvRuntimeEqual], + 'require("ajv/dist/runtime/parseJson").parseJson': ['ajvRuntimeparseJson', ajvRuntimeparseJson], + 'require("ajv/dist/runtime/parseJson").parseJsonNumber': ['ajvRuntimeparseJsonNumber', ajvRuntimeparseJsonNumber], + 'require("ajv/dist/runtime/parseJson").parseJsonString': ['ajvRuntimeparseJsonString', ajvRuntimeparseJsonString], + 'require("ajv/dist/runtime/quote").default': ['ajvRuntimeQuote', ajvRuntimeQuote], + // re2 by default is not in dependencies for ajv and so is likely not normally used + // 'require("ajv/dist/runtime/re2").default': ['ajvRuntimeRe2', ajvRuntimeRe2], + 'require("ajv/dist/runtime/timestamp").default': ['ajvRuntimeTimestamp', ajvRuntimeTimestamp], + 'require("ajv/dist/runtime/ucs2length").default': ['ajvRuntimeUcs2length', ajvRuntimeUcs2length], + 'require("ajv/dist/runtime/uri").default': ['ajvRuntimeUri', ajvRuntimeUri], + // formats + 'require("ajv-formats/dist/formats")': ['ajvFormats', ajvFormats], +}; + +const regexp = new RegExp( + Object.keys(validatorsBundleReplacements) + .map((key) => key.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')) + .join('|'), + 'g' +); + +function wrapAjvBundle(code: string) { + return `function(${Object.values(validatorsBundleReplacements) + .map(([name]) => name) + .join(', ')}){\nvar exports = {};\n${code.replace( + regexp, + (req) => validatorsBundleReplacements[req][0] + )};\nreturn exports;\n}`; +} + +const windowValidatorOnLoad = '__rjsf_validatorOnLoad'; +const schemas = new Map< + string, + { promise: Promise; resolve: (result: ValidatorFunctions) => void } +>(); +if (typeof window !== 'undefined') { + // @ts-ignore + window[windowValidatorOnLoad] = (loadedId: string, fn: (...args: unknown[]) => ValidatorFunctions) => { + const validator = fn(...Object.values(validatorsBundleReplacements).map(([, dep]) => dep)); + let validatorLoader = schemas.get(loadedId); + if (validatorLoader) { + validatorLoader.resolve(validator); + } else { + throw new Error(`Unknown validator loaded id="${loadedId}"`); + } + }; +} + +/** + * Evaluate precompiled validator in browser using script tag + * @param id Identifier to avoid evaluating the same code multiple times + * @param code Code generated server side using `compileSchemaValidatorsCode` + * @param nonce nonce attribute to be added to script tag (https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce#using_nonce_to_allowlist_a_script_element) + */ +export function evaluateValidator(id: string, code: string, nonce: string): Promise { + let maybeValidator = schemas.get(id); + if (maybeValidator) return maybeValidator.promise; + let resolveValidator: (result: ValidatorFunctions) => void; + const validatorPromise = new Promise((resolve) => { + resolveValidator = resolve; + }); + schemas.set(id, { + promise: validatorPromise, + resolve: resolveValidator!, + }); + + const scriptElement = document.createElement('script'); + + scriptElement.setAttribute('nonce', nonce); + scriptElement.text = `window["${windowValidatorOnLoad}"]("${id}", ${wrapAjvBundle(code)})`; + + document.body.appendChild(scriptElement); + return validatorPromise; +} +``` + +From React component this can be used as following: + +```tsx +let [precompiledValidator, setPrecompiledValidator] = React.useState(); +React.useEffect(() => { + evaluateValidator( + schemaId, // some schema id to avoid evaluating it multiple times + code, // result of compileSchemaValidatorsCode returned from the server + nonce // nonce script tag attribute to allow this ib content security policy for the page + ).then(setPrecompiledValidator); +}, [entityType.id]); + +if (!precompiledValidator) { + // render loading screen +} +const validator = createPrecompiledValidator(precompiledValidator, schema); +``` + +## Live validation + +By default, form data are only validated when the form is submitted or when a new `formData` prop is passed to the `Form` component. + +You can enable live form data validation by passing a `liveValidate` prop to the `Form` component, and set it to `true`. Then, every time a value changes within the form data tree (e.g. the user entering a character in a field), a validation operation is performed, and the validation results are reflected into the form state. + +Be warned that this is an expensive strategy, with possibly strong impact on performances. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: ['string'], + const: 'test', +}; + +const formData = 'a'; + +render(, document.getElementById('app')); +``` + +## Validate form programmatically + +It is possible to programmatically validate a form using the `validateForm()` function on `Form`. +Add a `ref` to your `Form` component and call the `validateForm()` method to validate the form programmatically. +The `validateForm()` method returns true if the form is valid, false otherwise. +If you have provided an `onError` callback it will be called with the list of errors when the `validatorForm()` method returns false. + +```tsx +import { createRef } from 'react'; +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const formRef = createRef(); +const onError = (errors) => alert(errors); + +const schema: RJSFSchema = { + type: 'string', +}; + +render(, document.getElementById('app')); + +if (formRef.current.validateForm()) { + alert('Form is valid'); +} +``` + +## HTML5 Validation + +By default, the form uses HTML5 validation. This may cause unintuitive results because the HTML5 validation errors (such as when a field is `required`) may be displayed before the form is submitted, and thus these errors will display differently from the react-jsonschema-form validation errors. You can turn off HTML validation by setting the `noHtml5Validate` to `true`. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + name: { + type: 'string', + required: true, + }, + }, +}; + +render(, document.getElementById('app')); +``` + +## Custom validation rules + +Form data is always validated against the JSON schema. + +But it is possible to define your own custom validation rules that will run in addition to (and after) the `validator` implementation. +This is especially useful when the validation depends on several interdependent fields. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +function customValidate(formData, errors, uiSchema) { + if (formData.pass1 !== formData.pass2) { + errors.pass2.addError("Passwords don't match"); + } + return errors; +} + +const schema: RJSFSchema = { + type: 'object', + properties: { + pass1: { type: 'string', minLength: 3 }, + pass2: { type: 'string', minLength: 3 }, + }, +}; + +render(, document.getElementById('app')); +``` + +> Notes: +> +> - The `customValidate()` function must implement the `CustomValidator` interface found in `@rjsf/utils`. +> - The `customValidate()` function must **always** return the `errors` object received as second argument. +> - The `customValidate()` function is called **after** the JSON schema validation. +> - The `customValidate()` function is passed the `uiSchema` as the third argument. This allows the `customValidate()` function to be able to derive additional information from it for generating errors. + +## Custom error messages + +Validation error messages are provided by the JSON Schema validation by default. +If you need to change these messages or make any other modifications to the errors from the JSON Schema validation, you can define a transform function that receives the list of JSON Schema errors and returns a new list. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +function transformErrors(errors, uiSchema) { + return errors.map((error) => { + if (error.name === 'pattern') { + error.message = 'Only digits are allowed'; + } + return error; + }); +} + +const schema: RJSFSchema = { + type: 'object', + properties: { + onlyNumbersString: { type: 'string', pattern: '^\\d*$' }, + }, +}; + +render( + , + document.getElementById('app') +); +``` + +> Notes: +> +> - The `transformErrors()` function must implement the `ErrorTransformer` interface found in `@rjsf/utils`. +> - The `transformErrors()` function must return the list of errors. Modifying the list in place without returning it will result in an error. +> - The `transformErrors()` function is passed the `uiSchema` as the second argument. This allows the `transformErrors()` function to be able to derive additional information from it for transforming errors. + +Each element in the `errors` list passed to `transformErrors` is a `RJSFValidationError` interface (in `@rjsf/utils`) and has the following properties: + +- `name`: optional name of the error, for example, "required" or "minLength" +- `message`: optional message, for example, "is a required property" or "should NOT be shorter than 3 characters" +- `params`: optional object with the error params returned by ajv ([see doc](https://github.com/ajv-validator/ajv/tree/6a671057ea6aae690b5967ee26a0ddf8452c6297#error-parameters) for more info). +- `property`: optional string in Javascript property accessor notation to the data path of the field with the error. For example, `.name` or `.first-name`. +- `schemaPath`: optional JSON pointer to the schema of the keyword that failed validation. For example, `#/fields/firstName/required`. (Note: this may sometimes be wrong due to a [bug in ajv](https://github.com/ajv-validator/ajv/issues/512)). +- `stack`: full error name, for example ".name is a required property". + +## Error List Display + +To take control over how the form errors are displayed, you can define an _error list template_ for your form. +This list is the form global error list that appears at the top of your forms. + +An error list template is basically a React stateless component being passed errors as props, so you can render them as you like: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, ErrorListProps } from "@rjsf/utils"; +import validator from "@rjsf/validator-ajv8"; + +function ErrorListTemplate(props: ErrorListProps) { + const { errors } = props; + return ( +
+

Custom error list

+
    + {errors.map(error => ( +
  • + {error.stack} +
  • + ))} +
+
+ ); +} + +const schema: RJSFSchema = { + type: "string", + const: "test" +}; + +render(( + +), document.getElementById("app")); +``` + +> Note: Your custom `ErrorList` template will only render when `showErrorList` is `top` or `botttom`. + +The following props are passed to `ErrorList` as defined by the `ErrorListProps` interface in `@rjsf/utils`: + +- `errors`: An array of the errors. +- `errorSchema`: The errorSchema constructed by `Form`. +- `schema`: The schema that was passed to `Form`. +- `uiSchema`: The uiSchema that was passed to `Form`. +- `formContext`: The `formContext` object that you passed to `Form`. + +## The case of empty strings + +When a text input is empty, the field in form data is set to `undefined`. +However, since `undefined` isn't a valid JSON value according to [the official JSON standard](https://www.ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf) (ECMA-404, Section 5), the values get stored as `null`. + +String fields that use `enum` and a `select` widget will have an empty option at the top of the options list that when selected will result in the field being `null`. + +One consequence of this is that if you have an empty string in your `enum` array, selecting that option in the `select` input will cause the field to be set to `null`, not an empty string. + +If you want to have the field set to a default value when empty you can provide a `ui:emptyValue` field in the `uiSchema` object. + +## Custom meta schema validation + +To have your schemas validated against any other meta schema than draft-07 (the current version of [JSON Schema](http://json-schema.org/)), make sure your schema has a `$schema` attribute that enables the validator to use the correct meta schema. +For example: + +```json +{ + "$schema": "http://json-schema.org/draft-04/schema#", + ... +} +``` + +Note that react-jsonschema-form supports JSON Schema draft-07 by default. +To support additional meta schemas, you can create and pass to the `Form` component a customized `@rjsf/validator-ajv8`: + +### additionalMetaSchemas + +The `additionalMetaSchemas` prop allows you to validate the form data against one (or more than one) JSON Schema meta schema, for example, JSON Schema draft-04. +You can import a meta schema as follows: + +```tsx +const metaSchemaDraft04 = require('ajv/lib/refs/json-schema-draft-04.json'); +``` + +In this example `schema` passed as props to `Form` component can be validated against draft-07 (default) and by draft-04 (added), depending on the value of `$schema` attribute. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv6'; + +const validator = customizeValidator({ + additionalMetaSchemas: [metaSchemaDraft04], +}); + +const schema: RJSFSchema = { + $schema: 'http://json-schema.org/draft-04/schema#', + type: 'string', +}; + +return ; +``` + +NOTE: This syntax works only for the `@rjsf/validator-ajv6` validator; if you only use the `draft-04` schema, and you want to use the `@rjsf/validator-ajv8` you can do the following: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import AjvDraft04 from 'ajv-draft-04'; + +const validator = customizeValidator({ AjvClass: AjvDraft04 }); + +const schema: RJSFSchema = { + $schema: 'http://json-schema.org/draft-04/schema#', + type: 'string', +}; + +return ; +``` + +### customFormats + +[Pre-defined semantic formats](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.7) are limited. +react-jsonschema-form adds two formats, `color` and `data-url`, to support certain [alternative widgets](./widgets.md). +To add formats of your own, you can create and pass to the `Form` component a customized `@rjsf/validator-ajv8`: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + format: 'phone-us', +}; + +const customFormats = { + 'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/, +}; + +const validator = customizeValidator({ customFormats }); + +render(, document.getElementById('app')); +``` + +Format values can be anything AJV's [`addFormat` method](https://github.com/ajv-validator/ajv/tree/6a671057ea6aae690b5967ee26a0ddf8452c6297#addformatstring-name-stringregexpfunctionobject-format---ajv) accepts. + +### Async validation + +Handling async errors is an important part of many applications. Support for this is added in the form of the `extraErrors` prop. + +For example, a request could be made to some backend when the user submits the form. If that request fails, the errors returned by the backend should be formatted like in the following example. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema, ErrorSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + foo: { + type: 'string', + }, + candy: { + type: 'object', + properties: { + bar: { + type: 'string', + }, + }, + }, + }, +}; + +const extraErrors: ErrorSchema = { + foo: { + __errors: ['some error that got added as a prop'], + }, + candy: { + bar: { + __errors: ['some error that got added as a prop'], + }, + }, +}; + +render(, document.getElementById('app')); +``` + +An important note is that these errors are "display only" and will not block the user from submitting the form again. + +### ajvOptionsOverrides + +In version 5, with the advent of the decoupling of the validation implementation from the `Form`, it is now possible to provide additional options to the `ajv` instance used within `@rjsf/validator-ajv8`. +For instance, if you need more information from `ajv` about errors via the `verbose` option, now you can turn it on! + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + format: 'phone-us', +}; + +const ajvOptionsOverrides = { + verbose: true, +}; + +const validator = customizeValidator({ ajvOptionsOverrides }); + +render(, document.getElementById('app')); +``` + +## Using the raw Ajv instance + +The `customizeValidator()` function returns the `AJV8Validator` (or `AJV6Validator` depending on the library you use) implementation class, which has an internal raw `ajv` instance within it. +If you need to do some deep customization of the instance using any of the `ajv` libraries (like `ajv-keywords`), you can do so using this raw instance as follows: + +```ts +import { customizeValidator } from '@rjsf/validator-ajv6'; +import ajvKeywords from 'ajv-keywords'; + +const validator = customizeValidator(); +ajvKeywords(validator.ajv, ['your-keyword']); + +// use your update validator with a `Form` +``` + +## Ajv8 validator differences + +There are a few differences in configuring the Ajv 8 validator. +First, there are many things to be aware of related to internal migration from Ajv 6 to 8; see the [migration guide](https://ajv.js.org/v6-to-v8-migration.html) for more information. + +One big difference is that Ajv 8 dropped support for any JSON Schema version before draft-06. +So if your schema is using an older format, you have to either upgrade it or stick with the `@rjsf/validator-ajv6`. + +Our implementation of `@rjsf/validator-ajv8` also utilizes Ajv's internal cache to avoid unnecessarily re-compiling schemas, which can be an expensive operation. The cache key is the schema `$id`. + +The `ajvOptionsOverrides` for the Ajv 8 validator are the ones supported by that version and not the Ajv 6 validator. +Second, the data formats previously provided in Ajv 6 now need to be added explicitly using the `ajv-formats` package. +A new `ajvFormatOptions` option is available on the `customizeValidator()` API to be able to configure this. +Additionally, a new `AjvClass` option is available on the `customizeValidator()` API to support using one of the other [JSON schema versions](https://ajv.js.org/json-schema.html#json-schema-versions) provided by Ajv 8 besides the `draft-07` default. +Finally, the Ajv 8 validator supports the localization of error messages. + +### ajvFormatOptions + +By default, ALL formats are being added to the default `@rjsf/validator-ajv8` that you get when you import it. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + format: 'email', +}; + +render(, document.getElementById('app')); +``` + +If you don't actually need any of the [ajv-formats](https://github.com/ajv-validator/ajv-formats#formats) and want to reduce the memory footprint, then you can turn it off as follows: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +const validator = customizeValidator({ ajvFormatOptions: false }); + +render(, document.getElementById('app')); +``` + +If you only need some of them, you can pass any of the [options](https://github.com/ajv-validator/ajv-formats#options) to the formatter: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + format: 'date', +}; + +const validator = customizeValidator({ ajvFormatOptions: ['date'] }); +// or +// const validator = customizeValidator({ ajvFormatOptions: { mode: "fast", formats: ["date"], keywords: true } }); + +render(, document.getElementById('app')); +``` + +### AjvClass + +By default, the `@rjsf/validator-ajv8` uses the `draft-07` schema version. +It is possible to use one of the other version it supports, like `draft-2019-09` or `draft-2020-12`. +NOTE: `draft-2020-12` has breaking changes and hasn't been fully tested with `@rjsf`. + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import Ajv2019 from 'ajv/dist/2019'; + +const schema: RJSFSchema = { + type: 'string', + format: 'date', +}; + +const validator = customizeValidator({ AjvClass: Ajv2019 }); +// or +// const validator = customizeValidator({ AjvClass: Ajv2020 }); + +render(, document.getElementById('app')); +``` + +### Localization (L10n) support + +The Ajv 8 validator supports the localization of error messages using [ajv-i18n](https://github.com/ajv-validator/ajv-i18n). +In addition, you may provide a custom solution by implementing a function that conforms to the `Localizer` interface if your language is not supported. + +```ts +import { ErrorObject } from 'ajv'; +/** The type describing a function that takes a list of Ajv `ErrorObject`s and localizes them + */ +export type Localizer = (errors?: null | ErrorObject[]) => void; +``` + +NOTE: The `ajv-i18n` validators implement the `Localizer` interface. + +#### Some examples + +Using a specific locale while including all of `ajv-i18n`: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import localizer from 'ajv-i18n'; + +const schema: RJSFSchema = { + type: 'string', +}; + +const validator = customizeValidator({}, localizer.it); + +render(, document.getElementById('app')); +``` + +Using a specific locale minimizing the bundle size + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import spanishLocalizer from 'ajv-i18n/localize/es'; + +const schema: RJSFSchema = { + type: 'string', +}; + +const validator = customizeValidator({}, spanishLocalizer); + +render(, document.getElementById('app')); +``` + +An example of a custom `Localizer` implementation: + +```tsx +import { Form } from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import { customizeValidator } from '@rjsf/validator-ajv8'; +import { ErrorObject } from 'ajv'; + +function localize_ru(errors: null | ErrorObject[] = []) { + if (!(errors && errors.length)) return; + errors.forEach(function (error) { + let outMessage = ''; + + switch (error.keyword) { + case 'pattern': { + outMessage = 'должно соответствовать образцу "' + error.params.pattern + '"'; + break; + } + case 'required': { + outMessage = 'поле обязательно для заполнения'; + break; + } + default: + outMessage = error.message; + } + + error.message = outMessage; + }); +} + +const schema: RJSFSchema = { + type: 'string', +}; + +const validator = customizeValidator({}, localize_ru); + +render(, document.getElementById('app')); +``` + +NOTES: + +- If you provided your own function, modify the list in place. +- You must process all the cases which you need by yourself. See the full list of possible cases [here](https://github.com/ajv-validator/ajv-i18n/blob/master/messages/index.js). +- Each element in the `errors` list passed to the custom function represent a **raw** error object returned by ajv ([see doc](https://github.com/ajv-validator/ajv/blob/master/docs/api.md#error-objects)). diff --git a/packages/docs/versioned_docs/version-5.24.10/usage/widgets.md b/packages/docs/versioned_docs/version-5.24.10/usage/widgets.md new file mode 100644 index 0000000000..63bf42518d --- /dev/null +++ b/packages/docs/versioned_docs/version-5.24.10/usage/widgets.md @@ -0,0 +1,248 @@ +# Widgets + +The uiSchema `ui:widget` property tells the form which UI widget should be used to render a field. + +Example: + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + done: { + type: 'boolean', + }, + }, +}; + +const uiSchema: UiSchema = { + done: { + 'ui:widget': 'radio', // could also be "select" + }, +}; + +render(, document.getElementById('app')); +``` + +Here's a list of supported alternative widgets for different JSON Schema data types: + +## For `boolean` fields + +- `radio`: a radio button group with `true` and `false` as selectable values; +- `select`: a select box with `true` and `false` as options; +- by default, a checkbox is used + +> Note: To set the labels for a boolean field, instead of using `true` and `false`, your schema can use `oneOf` with `const` values for both true and false, where you can specify the custom label in the `title` field. You will also need to specify a widget in your `uiSchema`. See the following example: + +schema: + +```json +{ + "properties": { + "booleanWithCustomLabels": { + "type": "boolean", + "oneOf": [ + { "const": true, "title": "Custom label for true" }, + { "const": false, "title": "Custom label for false" } + ] + } + } +} +``` + +uiSchema: + +```json +{ + "booleanWithCustomLabels": { + "ui:widget": "radio" // or "select" + } +} +``` + +## For `string` fields + +- `textarea`: a `textarea` element is used; +- `password`: an `input[type=password]` element is used; +- `color`: an `input[type=color]` element is used; +- by default, a regular `input[type=text]` element is used. + +### String formats + +The built-in string field also supports the JSON Schema `format` property, and will render an appropriate widget by default for the following string formats: + +- `email`: An `input[type=email]` element is used; +- `uri`: An `input[type=url]` element is used; +- `data-url`: By default, an `input[type=file]` element is used; in case the string is part of an array, multiple files will be handled automatically (see [File widgets](#file-widgets)). +- `date`: By default, an `input[type=date]` element is used; +- `date-time`: By default, an `input[type=datetime-local]` element is used. +- `time`: By default an `input[type=time]` element is used; + +![](https://i.imgur.com/xqu6Lcp.png) + +Please note that, even though they are standardized, `datetime-local`, `date` and `time` input elements are not supported by IE. If you plan on targeting IE, two alternative widgets are available: + +- `alt-datetime`: Six `select` elements are used to select the year, the month, the day, the hour, the minute and the second; +- `alt-date`: Three `select` elements are used to select the year, month and the day. + +![](https://i.imgur.com/VF5tY60.png) + +You can customize the list of years displayed in the `year` dropdown by providing a `yearsRange` property to `ui:options` in your uiSchema. +The range can be descending by specifying the larger value first. +It's also possible to remove the `Now` and `Clear` buttons with the `hideNowButton` and `hideClearButton` options. + +You can also, customize the order in which date input fields are displayed by providing `format` property to `ui:options` in your uiSchema, available values are `YMD`(default), `MDY` and `DMY`. + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'alt-datetime', + 'ui:options': { + yearsRange: [1980, 2030], + format: 'MDY', + hideNowButton: true, + hideClearButton: true, + }, +}; + +render(, document.getElementById('app')); +``` + +You can also specify negative values which will be treated relative to the current year, so if it is 2020 and the range is set as follows. + +``` + yearsRange: [-120, -18], +``` + +Years from 1900-2002 will be shown. You can also specify the dates with the higher date first to display dates in reverse order. + +``` + yearsRange: [2030, 1980], + ... + yearsRange: [-18, -120], +``` + +Years from 2030-1980 and 2002-1900, respectively will be shown. + +## For `number` and `integer` fields + +- `updown`: an `input[type=number]` updown selector; +- `range`: an `input[type=range]` slider; +- `radio`: a radio button group with enum values. This can only be used when `enum` values are specified for this input. +- By default, a regular `input[type=number]` element is used. + +> Note: If JSON Schema's `minimum`, `maximum` and `multipleOf` values are defined, the `min`, `max` and `step` input attributes values will take those values. + +## Hidden widgets + +It's possible to use a hidden widget for a field by setting its `ui:widget` uiSchema directive to `hidden`: + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema, UiSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'object', + properties: { + foo: { type: 'boolean' }, + }, +}; + +const uiSchema: UiSchema = { + foo: { 'ui:widget': 'hidden' }, +}; + +render(, document.getElementById('app')); +``` + +Notes: + +- Hiding widgets is only supported for `boolean`, `string`, `number` and `integer` schema types; +- A hidden widget takes its value from the `formData` prop. + +## File widgets + +This library supports a limited form of `input[type=file]` widgets, in the sense that it will propagate file contents to form data state as [data-url](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs)s. + +There are two ways to use file widgets. + +1. By declaring a `string` json schema type along a `data-url` [format](#string-formats): + +```tsx +import Form from '@rjsf/core'; +import { RJSFSchema } from '@rjsf/utils'; +import validator from '@rjsf/validator-ajv8'; + +const schema: RJSFSchema = { + type: 'string', + format: 'data-url', +}; + +render(, document.getElementById('app')); +``` + +2. By specifying a `ui:widget` field uiSchema directive as `file`: + +```ts +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'string', +}; + +const uiSchema: UiSchema = { + 'ui:widget': 'file', +}; +``` + +### Multiple files + +Multiple files selectors are supported by defining an array of strings having `data-url` as a format: + +```ts +import { RJSFSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'array', + items: { + type: 'string', + format: 'data-url', + }, +}; +``` + +> Note that storing large dataURIs into form state might slow rendering. + +### File widget input ref + +The included `FileWidget` exposes a reference to the `` element node as an `inputRef` component property. + +This allows you to programmatically trigger the browser's file selector, which can be used in a custom file widget. + +### `accept` option + +You can use the accept attribute to specify a filter for what file types the user can upload: + +```ts +import { RJSFSchema, UiSchema } from '@rjsf/utils'; + +const schema: RJSFSchema = { + type: 'string', + format: 'data-url', +}; + +const uiSchema: UiSchema = { + 'ui:options': { accept: '.pdf' }, +}; +``` diff --git a/packages/docs/versioned_sidebars/version-5.24.10-sidebars.json b/packages/docs/versioned_sidebars/version-5.24.10-sidebars.json new file mode 100644 index 0000000000..1fd014a287 --- /dev/null +++ b/packages/docs/versioned_sidebars/version-5.24.10-sidebars.json @@ -0,0 +1,8 @@ +{ + "docs": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/packages/docs/versions.json b/packages/docs/versions.json index d8a20442d6..b9b104075d 100644 --- a/packages/docs/versions.json +++ b/packages/docs/versions.json @@ -1,4 +1,5 @@ [ + "5.24.10", "4.2.3", "3.2.1" ]