diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ec3f3cc27..328e99ac57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,9 +15,31 @@ it according to semantic versioning. For example, if your PR adds a breaking cha should change the heading of the (upcoming) version to include a major version bump. --> -# v5.0.0 (coming soon) +# v5.0.0-beta.1 + +## Global changes across all themes: +- Node 16 is now the default node engine for all packages, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2687) +- Refactored all themes to use the new `@rjsf/utils` library functions and types +- Refactored the individual theme forms to consolidate `templates` as part of the fix for https://github.com/rjsf-team/react-jsonschema-form/issues/2526 + - All the work implementing the `BaseInputTemplate` should fix (https://github.com/rjsf-team/react-jsonschema-form/issues/2926, https://github.com/rjsf-team/react-jsonschema-form/issues/2889, https://github.com/rjsf-team/react-jsonschema-form/issues/2875, https://github.com/rjsf-team/react-jsonschema-form/issues/2223) + - Also made the display of `title` and `description` consistent across themes, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2481, https://github.com/rjsf-team/react-jsonschema-form/issues/2363, https://github.com/rjsf-team/react-jsonschema-form/issues/2219) + - This change also ensures that all templates are properly exported, resolving (https://github.com/rjsf-team/react-jsonschema-form/issues/2365) +- Bumped most devDependencies to the latest versions where possible +- Switched all repos `package.json` and `package-lock.json` files to be built and maintained by Node 16. +- Adding button templates help to change text for buttons (https://github.com/rjsf-team/react-jsonschema-form/issues/2082, https://github.com/rjsf-team/react-jsonschema-form/issues/2357) + ## @rjsf/utils -- clear errors on formData change when liveOmit=true when "additionalProperties: false" [issue 1507](https://github.com/rjsf-team/react-jsonschema-form/issues/1507) (https://github.com/rjsf-team/react-jsonschema-form/pull/2631) +- New package created by refactoring and converting to Typescript the `utils.js` file from `core` into independent functions. + - Resolves (https://github.com/rjsf-team/react-jsonschema-form/issues/1655, https://github.com/rjsf-team/react-jsonschema-form/issues/2480, https://github.com/rjsf-team/react-jsonschema-form/issues/2341) +- Updated `types` from `core` in `utils` to better match the implementation across all themes + - Included adding a bunch of new types for existing and new features + - The type updates should fix (https://github.com/rjsf-team/react-jsonschema-form/issues/2871, https://github.com/rjsf-team/react-jsonschema-form/issues/2673, https://github.com/rjsf-team/react-jsonschema-form/issues/2347, https://github.com/rjsf-team/react-jsonschema-form/issues/2186) +- Clear errors on `formData` change when `liveOmit=true` when "additionalProperties: false" [issue 1507](https://github.com/rjsf-team/react-jsonschema-form/issues/1507) (https://github.com/rjsf-team/react-jsonschema-form/pull/2631) + +## @rjsf/validator-ajv6 +- New package created by refactoring and converting to Typescript the `validator.js` file from `core` into independent functions as well as a class that implements the new `ValidatorType` interface. + - [#2693](https://github.com/rjsf-team/react-jsonschema-form/issues/2693). +- Added support for customizing the options passed to the creation of the `ajv` instance. ## @rjsf/validator-ajv6 - A **BREAKING CHANGE** to `toErrorList()` was made so that it takes `fieldPath: string[]` rather than `fieldName='root'` as part of the fix to (https://github.com/rjsf-team/react-jsonschema-form/issues/1596) @@ -26,6 +48,9 @@ should change the heading of the (upcoming) version to include a major version b - In addition, the extra information provided by AJV is no longer lost from the `errors` when merged with custom validation, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1596). ## @rjsf/core +- Converted core to Typescript (https://github.com/rjsf-team/react-jsonschema-form/issues/583) +- `ui:emptyValue` now works with selects (https://github.com/rjsf-team/react-jsonschema-form/issues/1041) +- Refactoring `utils.js` into the new `@rjsf/utils` fixes (https://github.com/rjsf-team/react-jsonschema-form/issues/2719) - **BREAKING CHANGE** Fix overriding core submit button className (https://github.com/rjsf-team/react-jsonschema-form/issues/2979) - Fix `ui:field` with anyOf or oneOf no longer rendered twice (#2890) - **BREAKING CHANGE** Fixed `anyOf` and `oneOf` getting incorrect, potentially duplicate ids when combined with array (https://github.com/rjsf-team/react-jsonschema-form/issues/2197) @@ -33,17 +58,55 @@ should change the heading of the (upcoming) version to include a major version b - Added `ui:duplicateKeySuffixSeparator` to customize how duplicate object keys are renamed when using `additionalProperties`. - The `extraErrors` are now consistently appended onto the end of the schema validation-based `errors` information that is returned via the `onErrors()` callback when submit fails. - In addition, the extra information provided by AJV is no longer stripped from the `errors` during the merge process, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1596). +- Fixed id generation for `RadioWidget` to no longer use random numbers fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2461) - Correctly call the `onChange` handler in the new set of props if it changed, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/1708). - Fixed race condition for `onChange` when `formData` is controlled prop, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/513), ## @rjsf/antd - Fix esm build to use `@rollup/plugin-replace` to replace `antd/lib` and `rc-picker/lib` with `antd/es` and `rc-picker/es` respectively, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2962) +## @rjsf/bootstrap-4 +- Bootstrap-4 `withTheme` customizations should work properly now (https://github.com/rjsf-team/react-jsonschema-form/issues/2058) +- `ArrayFieldTemplate` refactor seems to have fixed https://github.com/rjsf-team/react-jsonschema-form/issues/2775 +- Fix issues with `SelectField` (https://github.com/rjsf-team/react-jsonschema-form/issues/2616, https://github.com/rjsf-team/react-jsonschema-form/issues/2875) + +## @rjsf/chakra-ui +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) + +## @rjsf/material-ui +- 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) + - [#2774](https://github.com/rjsf-team/react-jsonschema-form/issues/2774) +- Material-UI TextWidget now respects `inputType` in uiSchema (https://github.com/rjsf-team/react-jsonschema-form/issues/2057) + - Also respects `step` for `number` type (https://github.com/rjsf-team/react-jsonschema-form/issues/2488) +- Material-UI UpDownWidget now support min/max/step (https://github.com/rjsf-team/react-jsonschema-form/issues/2022) +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) +- Select properly accepts true or false (https://github.com/rjsf-team/react-jsonschema-form/issues/2326) + +## @rjsf/mui +- 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) + - [#2774](https://github.com/rjsf-team/react-jsonschema-form/issues/2774) +- Material-UI TextWidget now respects `inputType` in uiSchema (https://github.com/rjsf-team/react-jsonschema-form/issues/2057) + - Also respects `step` for `number` type (https://github.com/rjsf-team/react-jsonschema-form/issues/2488) +- Material-UI UpDownWidget now support min/max/step (https://github.com/rjsf-team/react-jsonschema-form/issues/2022) +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) + ## @rjsf/semantic-ui - Fix missing error class on fields (https://github.com/rjsf-team/react-jsonschema-form/issues/2666) +- Fixed the `main` definition in `semantic-ui` to fix (https://github.com/withastro/astro/issues/4357) +- Properly handle the hidden field in this theme (https://github.com/rjsf-team/react-jsonschema-form/issues/2571) ## Dev / docs / playground - Demonstrate use of `ui:field` with `anyOf` (#2890) +- Playground now uses webpack 5 +- Corrected number field default (https://github.com/rjsf-team/react-jsonschema-form/issues/2358) # 4.2.1 * fix typo by @epicfaace in https://github.com/rjsf-team/react-jsonschema-form/pull/2854 diff --git a/docs/5.x upgrade guide.md b/docs/5.x upgrade guide.md index 56f8d261b8..eccd4101ad 100644 --- a/docs/5.x upgrade guide.md +++ b/docs/5.x upgrade guide.md @@ -11,14 +11,24 @@ There were several significant **breaking changes** in RJSF version 5 that were - [#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. + - [#2945](https://github.com/rjsf-team/react-jsonschema-form/issues/2945) - Fixed `anyOf` and `oneOf` getting incorrect, potentially duplicate ids when combined with array (https://github.com/rjsf-team/react-jsonschema-form/issues/2197) +### 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 16 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 (only `semantic-ui` is current restricted to React 16). -Unfortunately, there is required work pending to properly support React 18, so use with it at your own risk. +Unfortunately, there is required work pending to properly support React 18, so use it at your own risk. ### New packages @@ -43,9 +53,13 @@ Some of the most notable changes are: - `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`. - A new generic `F` (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 `ValidatorType` and `SchemaUtilsType` interfaces were added to support the decoupling of the validation implementation. +- 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. + +You can view all these [types](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/utils/src/types.ts) on Github. -You can view all these [types](https://github.com/rjsf-team/react-jsonschema-form/blob/rjsf-v5/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. @@ -64,7 +78,7 @@ import validator from "@rjsf/validator-ajv6"; const schema: RJSFSchema = { ... }; render(( -
+ ), document.getElementById("app")); ``` @@ -83,16 +97,109 @@ const customFormats: CustomValidatorOptionsType['customFormats'] = { ... }; const validator = customizeValidator({ additionalMetaSchemas, customFormats }); render(( - + +), document.getElementById("app")); +``` + +##### `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-ajv6"; + +// 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-ajv6"; + +// 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")); ``` -##### validate renamed -In version 5, the `validate` prop on `Form` was renamed to `customValidate` to avoid confusion with the new `validator` prop. +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](https://react-jsonschema-form.readthedocs.io/en/stable/advanced-customization/custom-templates) 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-ajv6"; + +// 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](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/utiltity-functions#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. 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. @@ -115,14 +222,14 @@ function YourField(props: FieldProps) { ```tsx // Change breaking-change function to schemaUtils instead, otherwise import from @rjsf/utils // import { utils } from '@rjsf/core'; <- version 4 -// const { isMultiSelect, retrieveSchema, getUiOptions } = utils; <- 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 isMultiSelect = isMultiSelect(schema, rootSchema); <- version 4 -// const newSchema = retrieveSchema(schema, rootSchema, formData); <- version 4 +// const newSchema = resolveSchema(schema, formData, rootSchema); <- version 4 const isMultiSelect = schemaUtils.isMultiSelect(schema); const newSchema: RJSFSchema = schemaUtils.retrieveSchema(schema, formData); const options = getUiOptions(uiSchema); @@ -132,11 +239,11 @@ function YourWidget(props: WidgetProps) { ``` #### validator.js -Because of the decoupling of validation from `@rjsf/core` this file was refactored into its own `@rjsf/validator-ajv` package. +Because of the decoupling of validation from `@rjsf/core` this file was refactored into its own `@rjsf/validator-ajv6` 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 use it to format the `stack` message. +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: @@ -165,8 +272,9 @@ The returned result from calling `toErrorList(errorSchema)` has changed as follo ##### 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) with the additional AJV error information besides the `stack` being lost when custom validation generated errors, which has been fixed. -Also, when `extraErrors` were provided, they were being inconsistently inserted into the `errors` list and the additional AJV error information besides the `stack` was also lost. +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`: diff --git a/docs/advanced-customization/custom-templates.md b/docs/advanced-customization/custom-templates.md index fdd257b9f1..dc445fee55 100644 --- a/docs/advanced-customization/custom-templates.md +++ b/docs/advanced-customization/custom-templates.md @@ -2,21 +2,53 @@ 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) | [FieldTemplate](#FieldTemplate) / [ArrayFieldTemplate](#ArrayFieldTemplate) / [ObjectFieldTemplate](#ObjectFieldTemplate) | [Custom Widgets](custom-widgets-fields.md) +| | 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. | +| [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. | +| [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. You can also customize arrays by specifying a widget in the relevant `ui:widget` schema, more details over on [Custom Widgets](../usage/arrays.md#custom-widgets). +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](../usage/arrays.md#custom-widgets). - -```jsx +```tsx +import { ArrayFieldTemplateProps } from "@rjsf/utils"; import validator from '@rjsf/validator-ajv6'; const schema = { @@ -26,7 +58,7 @@ const schema = { } }; -function ArrayFieldTemplate(props) { +function ArrayFieldTemplate(props: ArrayFieldTemplateProps) { return (
{props.items.map(element => element.children)} @@ -36,7 +68,7 @@ function ArrayFieldTemplate(props) { } render(( - + ), document.getElementById("app")); ``` @@ -48,12 +80,10 @@ const uiSchema = { } ``` -Please see [customArray.js](https://github.com/rjsf-team/react-jsonschema-form/blob/4542cd254ffdc6dfaf55e8c9f6f17dc900d0d041/packages/playground/src/samples/customArray.js) for another example. +Please see [customArray.js](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/playground/src/samples/customArray.js) for another example. The following props are passed to each `ArrayFieldTemplate`: -- `DescriptionField`: The `DescriptionField` from the registry (in case you wanted to utilize it). -- `TitleField`: The `TitleField` from the registry (in case you wanted to utilize it). - `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. @@ -62,11 +92,13 @@ The following props are passed to each `ArrayFieldTemplate`: - `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. +- `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`: @@ -84,8 +116,338 @@ The following props are part of each element in `items`: - `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. +- `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 } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "array", + items: { + type: "string" + } +}; + +function ArrayFieldDescriptionTemplate(props: ArrayFieldDescriptionProps) { + const { description, idSchema } = props; + const id = `${idSchema.$id}__description`; + return ( +
+ Description + {description} +
+ ); +} + +render(( + +), document.getElementById("app")); +``` + +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. + +```js +const 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. +- `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 } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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. +- `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. +- `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) -> Note: Array and object field templates are always rendered inside of the FieldTemplate. To fully customize an array field template, you may need to specify both `ui:FieldTemplate` and `ui:ArrayFieldTemplate`. +```tsx +import { ArrayFieldTitleTemplateProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + type: "array", + items: { + type: "string" + } +}; + +function ArrayFieldTitleTemplate(props: ArrayFieldTitleProps) { + const { description, idSchema } = props; + const id = `${idSchema.$id}__title`; + return ( +

+ {title} +

+ ); +} + +render(( + +), document.getElementById("app")); +``` + +You also can provide your own template to a uiSchema by specifying a `ui:ArrayFieldDescriptionTemplate` property. + +```js +const 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. +- `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 { getInputProps, WidgetProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +import CustomTextInput from '../CustomTextInput'; + +const schema = { + type: "string", + title: "My input", + description: "input description" +}; + +function BaseInputTemplate(props: WidgetProps) { + const { + schema, + id, + options, + label, + value, + type, + placeholder, + required, + disabled, + readonly, + autofocus, + onChange, + onBlur, + onFocus, + rawErrors, + hideError, + uiSchema, + registry, + formContext, + ...rest + } = props; + const onTextChange = ({ target: { value: val } }: React.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 } }: React.FocusEvent) => onBlur(id, val); + const onTextFocus = ({ target: { value: val } }: React.FocusEvent) => onFocus(id, val); + + const inputProps = { ...rest, ...getInputProps(schema, type, options) }; + const hasError = rawErrors.length > 0 && !hideError; + + return ( + + ); +} + +render(( + +), document.getElementById("app")); +``` + +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; +- `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`: 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 } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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. +- `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 } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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` ## FieldTemplate @@ -93,14 +455,15 @@ To take control over the inner organization of each field (each form row), you c A field template is basically a React stateless component being passed field-related props, allowing you to structure your form row as you like. -```jsx +```tsx +import { FieldTemplateProps } from "@rjsf/utils"; import validator from "@rjsf/validator-ajv6"; const schema = { type: "string" }; -function CustomFieldTemplate(props) { +function CustomFieldTemplate(props: FieldTemplateProps) { const {id, classNames, label, help, required, description, errors, children} = props; return (
@@ -114,7 +477,7 @@ function CustomFieldTemplate(props) { } render(( - + ), document.getElementById("app")); ``` @@ -136,6 +499,7 @@ The following props are passed to a custom field template component: - `description`: A component instance rendering the field description, if one is defined (this will use any [custom `DescriptionField`](#custom-descriptions) defined). - `rawDescription`: A string containing any `ui:description` uiSchema directive defined. - `children`: The field or widget component instance for this field row. +- `hideError`: A boolean value stating if the field is hiding its errors. - `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. @@ -146,7 +510,6 @@ The following props are passed to a custom field template component: - `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. -- `fields`: An array containing all Form's fields including your [custom fields](#custom-field-components) and the built-in fields. - `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. @@ -158,7 +521,8 @@ The following props are passed to a custom field template component: ## ObjectFieldTemplate -```jsx +```tsx +import { ObjectFieldTemplateProps } from "@rjsf/utils"; import validator from "@rjsf/validator-ajv6"; const schema = { @@ -175,7 +539,7 @@ const schema = { } }; -function ObjectFieldTemplate(props) { +function ObjectFieldTemplate(props: ObjectFieldTemplateProps) { return (
{props.title} @@ -186,7 +550,7 @@ function ObjectFieldTemplate(props) { } render(( - + ), document.getElementById("app")); ``` @@ -198,12 +562,10 @@ const uiSchema = { }; ``` -Please see [customObject.js](https://github.com/rjsf-team/react-jsonschema-form/blob/4542cd254ffdc6dfaf55e8c9f6f17dc900d0d041/packages/playground/src/samples/customObject.js) for a better example. +Please see [customObject.js](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/playground/src/samples/customObject.js) for a better example. The following props are passed to each `ObjectFieldTemplate` as defined by the `ObjectFieldTemplateProps` in `@rjsf/utils`: -- `DescriptionField`: The `DescriptionField` from the registry (in case you wanted to utilize it). -- `TitleField`: The `TitleField` from the registry (in case you wanted to utilize it). - `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. @@ -211,6 +573,7 @@ The following props are passed to each `ObjectFieldTemplate` as defined by the ` - `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. @@ -226,4 +589,243 @@ The following props are part of each element in `properties`: - `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 of the FieldTemplate. To fully customize an object field template, you may need to specify both `ui:FieldTemplate` and `ui:ObjectFieldTemplate`. +> 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 { TitleFieldProps } from "@rjsf/utils"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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. +- `uiSchema`: The uiSchema object for this 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 { UnsupportedFieldProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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. + +## 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. + +### 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 } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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 } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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 } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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 } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/form-props#children) of the `Form` should you so choose. + +```tsx +import React from "react"; +import { getSubmitButtonOptions, SubmitButtonProps } from "@rjsf/utils"; +import { FormattedMessage } from "react-intl"; +import validator from '@rjsf/validator-ajv6'; + +const schema = { + 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`. diff --git a/docs/advanced-customization/custom-themes.md b/docs/advanced-customization/custom-themes.md index 699f5449e2..ac2e493196 100644 --- a/docs/advanced-customization/custom-themes.md +++ b/docs/advanced-customization/custom-themes.md @@ -1,6 +1,7 @@ # 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. +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 @@ -19,7 +20,12 @@ const Demo = () => ( ``` ## Theme object properties -The Theme object consists of the same properties as the rjsf `Form` component (such as **widgets** and **fields**). The themed-Form component merges together any theme-specific **widgets** and **fields** with the default **widgets** and **fields**. 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** or **fields** when using the custom-themed HOC component; you can make the essentially redefine the default Form by simply doing `const Form = withTheme({});`. +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](/advanced-customization/#custom-widgets-and-fields). @@ -40,14 +46,14 @@ const myWidgets = { myCustomWidget: MyCustomWidget }; -const ThemeObject = {widgets: myWidgets}; +const ThemeObject = { widgets: myWidgets }; export default ThemeObject; ``` -The above can be similarly done for **fields**. +The above can be similarly done for **fields** and **templates**. ### Templates -Each template should be passed directly into the theme object just as you would into the rjsf Form component. Here is an example of how to use a custom [ArrayFieldTemplate](/advanced-customization/#array-field-template) and [ErrorListTemplate](/advanced-customization/#error-list-template) in the theme object: +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](/advanced-customization/#array-field-template) and [ErrorListTemplate](/advanced-customization/#error-list-template) in the theme object: ```jsx function MyArrayFieldTemplate(props) { return ( @@ -72,8 +78,10 @@ function MyErrorListTemplate(props) { } const ThemeObject = { - ArrayFieldTemplate: MyArrayFieldTemplate, - ErrorList: MyErrorListTemplate, + templates: { + ArrayFieldTemplate: MyArrayFieldTemplate, + ErrorListTemplate: MyErrorListTemplate, + }, widgets: myWidgets }; @@ -81,10 +89,12 @@ export default ThemeObject; ``` ## Overriding other Form props -Just as the theme can override **widgets**, **fields**, any of the field templates, and set default values to properties like **showErrorList**, you can do the same with the instance of the withTheme() Form component. +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. ```jsx const ThemeObject = { - ArrayFieldTemplate: MyArrayFieldTemplate, + templates: { + ArrayFieldTemplate: MyArrayFieldTemplate, + }, fields: myFields, showErrorList: false, widgets: myWidgets diff --git a/docs/api-reference/form-props.md b/docs/api-reference/form-props.md index 9ebb7725df..0fac4cc2af 100644 --- a/docs/api-reference/form-props.md +++ b/docs/api-reference/form-props.md @@ -10,10 +10,6 @@ The value of this prop will be passed to the `action` [HTML attribute on the for 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. -## ArrayFieldTemplate - -React component used to customize how all arrays are rendered on the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. - ## 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). @@ -107,10 +103,6 @@ You can pass a React component to this prop to customize how form errors are dis Dictionary of registered fields in the form. See [Custom Widgets and Fields](../advanced-customization/custom-widgets-fields.md) for more information. -## FieldTemplate - -React component used to customize each field of the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. - ## 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. @@ -191,10 +183,6 @@ If set to true, turns off HTML5 validation on the form. Set to `false` by defaul If set to true, turns off all validation. Set to `false` by default. -## ObjectFieldTemplate - -React component used to customize how all objects are rendered in the form. See [Custom Templates](../advanced-customization/custom-templates.md) for more information. - ## 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. @@ -281,6 +269,10 @@ const CustomForm = props => 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. diff --git a/docs/api-reference/uiSchema.md b/docs/api-reference/uiSchema.md index c2101a5441..219826ae8a 100644 --- a/docs/api-reference/uiSchema.md +++ b/docs/api-reference/uiSchema.md @@ -5,22 +5,23 @@ A UI schema is basically an object literal providing information on **how** the The uiSchema object follows the tree structure of the form field hierarchy, and defines how each property should be rendered. -Note that every property within uiSchema can be rendered in one of two ways: `{"ui:options": {[property]: [value]}}`, or `{"ui:[property]": value}`. +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 uiSchemas are equivalent: +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" - } + "norender": false, + "submitText": "Submit" + } } ``` @@ -29,6 +30,7 @@ In other words, the following uiSchemas are equivalent: "ui:options": { "title": "Title", "description": "Description", + "classNames": "my-class", "submitButtonOptions": { "props": { "disabled": false, @@ -41,14 +43,57 @@ In other words, the following uiSchemas are equivalent: } ``` -## classNames +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/master/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 3 properties that exist in a `UiSchema` that will not be found in an inner `ui:options` object. + +### 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: + +```js +const 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](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/custom-widgets-fields#custom-field-components) for more information about how to use this property. + +### 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](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/arrays#array-item-uiSchema-options) + +### widget + +The `ui:field` 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](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/custom-widgets-fields) for more information about how to use this property. + +### classNames The uiSchema object accepts a `classNames` property for each field of the schema: ```jsx const uiSchema = { title: { - classNames: "task-title foo-bar" + "ui:classNames": "task-title foo-bar" } }; ``` @@ -64,7 +109,19 @@ Will result in:
``` -## autofocus +### 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). + +```js +const schema = {type: "string"}; +const 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`. @@ -76,7 +133,7 @@ const uiSchema = { } ``` -## description +### description Sometimes it's convenient to change the description of a field. This is the purpose of the `ui:description` uiSchema directive: @@ -88,13 +145,17 @@ const uiSchema = { }; ``` -## disabled +### 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. -## enumDisabled +### 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. @@ -109,7 +170,7 @@ const uiSchema={ } ``` -## help +### 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: @@ -125,7 +186,7 @@ const uiSchema = { 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 +### 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. @@ -133,7 +194,7 @@ If you need to enable the default error display of a child in the hierarchy afte 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 +### inputType To change the input type (for example, `tel` or `email`) you can specify the `inputType` in the `ui:options` uiSchema directive. @@ -146,7 +207,7 @@ const uiSchema = { }; ``` -## label +### label Field labels are rendered by default. Labels may be omitted by setting the `label` option to `false` in the `ui:options` uiSchema directive. @@ -165,11 +226,11 @@ render(( ), document.getElementById("app")); ``` -## order +### order This property allows you to reorder the properties that are shown for a particular object. See [Objects](../usage/objects.md) for more information. -## placeholder +### placeholder You can add placeholder text to an input by using the `ui:placeholder` uiSchema directive: @@ -201,25 +262,13 @@ render(( ), document.getElementById("app")); ``` -## readonly +### 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. -## 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: - -```js -const uiSchema = { - "ui:rootFieldId": "myform" -}; -``` - -This will make all widgets have an id prefixed with `myform`. - -## rows +### rows You can set the initial height of a textarea widget by specifying `rows` option. @@ -228,8 +277,8 @@ import validator from "@rjsf/validator-ajv6"; const schema = {type: "string"}; const uiSchema = { - "ui:widget": "textarea", "ui:options": { + widget: "textarea", rows: 15 } }; @@ -239,7 +288,7 @@ render(( ), document.getElementById("app")); ``` -## title +### title Sometimes it's convenient to change a field's title. This is the purpose of the `ui:title` uiSchema directive: @@ -251,30 +300,29 @@ const uiSchema = { }; ``` -## submitButtonOptions +### 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 +#### `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 +#### `submitText` option You can use this option to change the text of the submit button. Set to "Submit" by default. -### `props` section +#### `props` section You can pass any other prop to the submit button if you want, via this section. - -#### `disabled` prop +##### `disabled` prop You can use this option to disable the submit button. -#### `className` prop +##### `className` prop You can use this option to specify a class name for the submit button. diff --git a/docs/api-reference/utility-functions.md b/docs/api-reference/utility-functions.md index cb57851a11..371b82de4c 100644 --- a/docs/api-reference/utility-functions.md +++ b/docs/api-reference/utility-functions.md @@ -10,13 +10,13 @@ There is also a helper [function](#schema-utils-creation-function) used to creat 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/rjsf-v5/packages/utils/src/constants.ts). +These constants can be found on Github [here](https://github.com/rjsf-team/react-jsonschema-form/blob/master/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/rjsf-v5/packages/utils/src/types.ts). +These types can be found on Github [here](https://github.com/rjsf-team/react-jsonschema-form/blob/master/packages/utils/src/types.ts). ## Non-Validator utility functions @@ -91,6 +91,17 @@ Otherwise return the sub-schema. Also deals with nested `$ref`s in the sub-schem #### Throws - Error indicating that no schema for that reference exists +### getInputProps() +Using the `schema`, `defaultType` and `options`, extract out the props for the element that make sense. + +#### Parameters +- schema: RJSFSchema - The schema for the field provided by the widget +- [defaultType]: string - 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 + ### 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: @@ -124,6 +135,18 @@ Get all passed options from ui:options, and ui:, returning them in a #### Returns - UIOptionsType: An object containing all of the `ui:xxx` options with the stripped off +### getTemplate, T = any, F = 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 @@ -301,13 +324,15 @@ Parses the `dateString` into a `DateObject`, including the time information when #### Throws - Error when the date cannot be parsed from the string -### processSelectValue() +### processSelectValue() Returns the real value for a select widget due to a silly limitation in the DOM which causes option change event values to always be retrieved as strings. Uses the `schema` to help determine the value's true type. +If the value is an empty string, then the `emptyValue` from the `options` is returned, falling back to undefined. #### Parameters - schema: RJSFSchema - The schema to used to determine the value's true type - [value]: any - The value to convert +- [options]: UIOptionsType - The UIOptionsType from which to potentially extract the `emptyValue` #### Returns - string | boolean | number | string[] | boolean[] | number[] | undefined: The `value` converted to the proper type diff --git a/docs/usage/arrays.md b/docs/usage/arrays.md index 800c85aea6..761f03abaf 100644 --- a/docs/usage/arrays.md +++ b/docs/usage/arrays.md @@ -92,7 +92,7 @@ render(( ), document.getElementById("app")); ``` -## Array item options +## Array item uiSchema options ### `orderable` option diff --git a/docs/usage/widgets.md b/docs/usage/widgets.md index 468897a21d..01c4cdead9 100644 --- a/docs/usage/widgets.md +++ b/docs/usage/widgets.md @@ -118,7 +118,7 @@ render(( * `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=text]` element is used. + * 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. diff --git a/packages/core/src/components/templates/UnsupportedField.tsx b/packages/core/src/components/templates/UnsupportedField.tsx index 48913cec08..91f822a490 100644 --- a/packages/core/src/components/templates/UnsupportedField.tsx +++ b/packages/core/src/components/templates/UnsupportedField.tsx @@ -1,7 +1,7 @@ import React from "react"; import { UnsupportedFieldProps } from "@rjsf/utils"; -/** The `UnsupportedField` component is use to render a field in the schema is one that is not supported by +/** The `UnsupportedField` component is used to render a field in the schema is one that is not supported by * react-jsonschema-form. * * @param props - The `FieldProps` for this template diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index c0be064336..aa0ea4ff29 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -253,6 +253,8 @@ export interface FieldProps autofocus?: boolean; /** A boolean value stating if the field is disabled */ disabled: boolean; + /** A boolean value stating if the field is hiding its errors */ + hideError?: boolean; /** A boolean value stating if the field is read-only */ readonly: boolean; /** The required status of this field */ @@ -430,6 +432,8 @@ export type ArrayFieldTemplateProps = { readonly?: boolean; /** A boolean value stating if the array is required */ required?: boolean; + /** A boolean value stating if the field is hiding its errors */ + hideError?: boolean; /** The schema object for this array */ schema: RJSFSchema; /** The uiSchema object for this array field */ @@ -476,6 +480,8 @@ export type ObjectFieldTemplateProps = { readonly?: boolean; /** A boolean value stating if the object is required */ required?: boolean; + /** A boolean value stating if the field is hiding its errors */ + hideError?: boolean; /** The schema object for this object */ schema: RJSFSchema; /** The uiSchema object for this object field */ @@ -511,6 +517,8 @@ export interface WidgetProps disabled?: boolean; /** A boolean value stating if the widget is read-only */ readonly?: boolean; + /** A boolean value stating if the widget is hiding its errors */ + hideError?: boolean; /** A boolean value stating if the widget should autofocus */ autofocus?: boolean; /** The placeholder for the widget, if any */