diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c4f19f344..d625901c1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,7 +67,9 @@ should change the heading of the (upcoming) version to include a major version b - Updated the `ArrayFieldTemplateItemType` to add the new `totalItems` and `canAdd` props, fixing [#3315](https://github.com/rjsf-team/react-jsonschema-form/issues/3315) ## Dev / docs / playground -- Fixed the documentation for `ArrayFieldItemTemplate`, `SubmitButtonProps` and `IconButtonProps` as part of the fix for [#3314](https://github.com/rjsf-team/react-jsonschema-form/issues/3314) and [#3315](https://github.com/rjsf-team/react-jsonschema-form/issues/3315) +- Fixed the documentation for `ArrayFieldItemTemplate`, `SubmitButtonProps` and `IconButtonProps` as part of the fix for [#3314](https://github.com/rjsf-team/react-jsonschema-form/issues/3314) and [#3315](https://github.com/rjsf-team/react-jsonschema-form/issues/3315) +- Updated the documentation in `form-props.md` for `children`, fixing [#3322](https://github.com/rjsf-team/react-jsonschema-form/issues/3322) +- Added new `typescript.md` documentation to `Advanced Customization` describing how to use custom generics as part of the fix for [#3072](https://github.com/rjsf-team/react-jsonschema-form/issues/3072) # 5.0.0-beta-15 diff --git a/docs/advanced-customization/custom-templates.md b/docs/advanced-customization/custom-templates.md index 8f99ca150c..5ee3819a17 100644 --- a/docs/advanced-customization/custom-templates.md +++ b/docs/advanced-customization/custom-templates.md @@ -811,11 +811,10 @@ function WrapIfAdditionalTemplate( onBlur={function (event) { onKeyChange(event.target.value) } } defaultValue={label} />
{children}
- - + ); } diff --git a/docs/advanced-customization/typescript.md b/docs/advanced-customization/typescript.md new file mode 100644 index 0000000000..bdbca8849f --- /dev/null +++ b/docs/advanced-customization/typescript.md @@ -0,0 +1,273 @@ +# 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< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any +>(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 { validator } 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 = {}; + +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 { validator } 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" } + } +}; + +render(( + schema={schema} validator={validator} /> +), document.getElementById("app")); + +// Alternatively since you have the type, you could also use this +// 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 { validator } 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, + } +}; + +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 { validator } 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 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 { validator } 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); + +// 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. \ No newline at end of file diff --git a/docs/api-reference/form-props.md b/docs/api-reference/form-props.md index 6b9b1aad9f..b4a0d0d17d 100644 --- a/docs/api-reference/form-props.md +++ b/docs/api-reference/form-props.md @@ -26,7 +26,7 @@ The value of this prop will be passed to the `class` [HTML attribute on the form 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/#submitbuttonoptions) and the [SubmitButton Template](../advanced-customization/custom-templates/#submitbutton) documentation. +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 { RJSFSchema } from "@rjsf/utils"; diff --git a/mkdocs.yml b/mkdocs.yml index 935216f927..cbe8f6dc28 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,6 +7,7 @@ extra_javascript: [main.js] nav: - Introduction: index.md - Quickstart: quickstart.md + - Contributing: contributing.md - JSON schema: - Single fields: usage/single.md - Objects: usage/objects.md @@ -23,18 +24,18 @@ nav: - Custom Templates: advanced-customization/custom-templates.md - Custom Themes: advanced-customization/custom-themes.md - Other Internals: advanced-customization/internals.md - - Contributing: contributing.md + - Typescript Support: advanced-customization/typescript.md - API Reference: - General uiSchema Reference: api-reference/uiSchema.md - semantic-ui uiSchema Reference: api-reference/themes/semantic-ui/uiSchema.md - chakra-ui uiSchema Reference: api-reference/themes/chakra-ui/uiSchema.md - "<Form /> props": api-reference/form-props.md - Utility functions: api-reference/utility-functions.md - - 5.x Migration: 5.x upgrade guide.md - - 4.x Migration: 4.x upgrade guide.md - - 3.x Migration: 3.x upgrade guide.md - - 2.x Migration: 2.x upgrade guide.md - - Contributing: contributing.md + - Migration Guides: + - 5.x Migration: 5.x upgrade guide.md + - 4.x Migration: 4.x upgrade guide.md + - 3.x Migration: 3.x upgrade guide.md + - 2.x Migration: 2.x upgrade guide.md markdown_extensions: - toc: