diff --git a/CHANGELOG.md b/CHANGELOG.md index 453e899d1e..2c55056e91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,11 +21,16 @@ should change the heading of the (upcoming) version to include a major version b ## @rjsf/core - Fix default value population when switching between options in `MultiSchemaField` [#4375](https://github.com/rjsf-team/react-jsonschema-form/pull/4375). Fixes [#4367](https://github.com/rjsf-team/react-jsonschema-form/issues/4367) +- Updated `ObjectField` and `CheckboxWidget` to render markdown in the description when `enableMarkdownInDescription` is set to `true`, fixing [#3975](https://github.com/rjsf-team/react-jsonschema-form/issues/3975) ## @rjsf/validator-ajv8 - Fixed issue where `ui:title` in anyOf/oneOf is not shown in error messages. Fixes [#4368](https://github.com/rjsf-team/react-jsonschema-form/issues/4368) +## Dev / docs / playground + +- Fixed typo in `package.json` + # 5.23.1 ## @rjsf/chakra-ui diff --git a/package.json b/package.json index 5852ea996c..19f78c2571 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "prepare": "husky install", "format": "prettier --write .", "format-check": "prettier --check .", - "bump-all-packages": "echo 'NOTE: Make sure to sanity check the playground locally before commiting changes' && npm update --save && npm install && npm run lint && npm run build && npm run test", + "bump-all-packages": "echo 'NOTE: Make sure to sanity check the playground locally before committing changes' && npm update --save && npm install && npm run lint && npm run build && npm run test", "bump-peer-deps": "node scripts/bump-peer-deps.js", "refresh-node-modules": "rimraf packages/*/node_modules && rimraf node_modules && npm install", "commit-package-changes": "git add package-lock.json packages/*/package*.json && cross-env CI=skipPrecommit git commit -m 'updated package*.json after versioning' && git push", diff --git a/packages/antd/src/templates/DescriptionField/index.tsx b/packages/antd/src/templates/DescriptionField/index.tsx index ba29039282..4a2a36fc7b 100644 --- a/packages/antd/src/templates/DescriptionField/index.tsx +++ b/packages/antd/src/templates/DescriptionField/index.tsx @@ -1,4 +1,4 @@ -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; /** The `DescriptionField` is the template to use to render the description of a field * @@ -9,9 +9,13 @@ export default function DescriptionField< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any >(props: DescriptionFieldProps) { - const { id, description } = props; + const { id, description, registry, uiSchema } = props; if (!description) { return null; } - return {description}; + return ( + + + + ); } diff --git a/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx b/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx index dadfb29565..c300bbc355 100644 --- a/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx +++ b/packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx @@ -1,19 +1,19 @@ -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; export default function DescriptionField< T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any ->({ id, description }: DescriptionFieldProps) { - if (description) { - return ( -
-
- {description} -
-
- ); +>({ id, description, registry, uiSchema }: DescriptionFieldProps) { + if (!description) { + return null; } - return null; + return ( +
+
+ +
+
+ ); } diff --git a/packages/chakra-ui/src/DescriptionField/DescriptionField.tsx b/packages/chakra-ui/src/DescriptionField/DescriptionField.tsx index 3d998dbc62..42253bb10e 100644 --- a/packages/chakra-ui/src/DescriptionField/DescriptionField.tsx +++ b/packages/chakra-ui/src/DescriptionField/DescriptionField.tsx @@ -1,22 +1,18 @@ -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; import { Text } from '@chakra-ui/react'; export default function DescriptionField< T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any ->({ description, id }: DescriptionFieldProps) { +>({ id, description, registry, uiSchema }: DescriptionFieldProps) { if (!description) { return null; } - if (typeof description === 'string') { - return ( - - {description} - - ); - } - - return <>{description}; + return ( + + + + ); } diff --git a/packages/core/src/components/fields/SchemaField.tsx b/packages/core/src/components/fields/SchemaField.tsx index c7b8db77e5..6e6fed21cc 100644 --- a/packages/core/src/components/fields/SchemaField.tsx +++ b/packages/core/src/components/fields/SchemaField.tsx @@ -22,7 +22,6 @@ import { } from '@rjsf/utils'; import isObject from 'lodash/isObject'; import omit from 'lodash/omit'; -import Markdown from 'markdown-to-jsx'; /** The map of component type to FieldName */ const COMPONENT_TYPES: { [key: string]: string } = { @@ -201,11 +200,6 @@ function SchemaFieldRender{description} - ) : ( - description - ); const help = uiOptions.help; const hidden = uiOptions.widget === 'hidden'; @@ -254,7 +248,7 @@ function SchemaFieldRender(id)} - description={richDescription} + description={description} schema={schema} uiSchema={uiSchema} registry={registry} diff --git a/packages/core/src/components/templates/DescriptionField.tsx b/packages/core/src/components/templates/DescriptionField.tsx index 242500611a..e716751468 100644 --- a/packages/core/src/components/templates/DescriptionField.tsx +++ b/packages/core/src/components/templates/DescriptionField.tsx @@ -1,4 +1,4 @@ -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; /** The `DescriptionField` is the template to use to render the description of a field * @@ -9,21 +9,13 @@ export default function DescriptionField< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any >(props: DescriptionFieldProps) { - const { id, description } = props; + const { id, description, registry, uiSchema } = props; if (!description) { return null; } - if (typeof description === 'string') { - return ( -

- {description} -

- ); - } else { - return ( -
- {description} -
- ); - } + return ( +
+ +
+ ); } diff --git a/packages/core/test/ObjectField.test.jsx b/packages/core/test/ObjectField.test.jsx index fc0cfd08ab..fbd80008d3 100644 --- a/packages/core/test/ObjectField.test.jsx +++ b/packages/core/test/ObjectField.test.jsx @@ -1203,4 +1203,76 @@ describe('ObjectField', () => { }); }); }); + + describe('markdown', () => { + const schema = { + title: 'A list of tasks', + type: 'object', + properties: { + tasks: { + description: 'New *description*, with some Markdown.', + type: 'object', + title: 'Tasks', + properties: { + details: { + type: 'string', + title: 'Task details', + description: 'Description to renders Markdown **correctly**.', + }, + has_markdown: { + type: 'boolean', + description: 'Checkbox with some `markdown`!', + }, + }, + }, + }, + }; + + const uiSchema = { + tasks: { + 'ui:enableMarkdownInDescription': true, + details: { + 'ui:enableMarkdownInDescription': true, + 'ui:widget': 'textarea', + }, + has_markdown: { + 'ui:enableMarkdownInDescription': true, + }, + }, + }; + + it('should render markdown in description when enableMarkdownInDescription is set to true', () => { + const { node } = createFormComponent({ schema, uiSchema }); + + const { innerHTML: rootInnerHTML } = node.querySelector('form .form-group .form-group .field-description'); + expect(rootInnerHTML).to.contains('New description, with some Markdown.'); + + const { innerHTML: detailsInnerHTML } = node.querySelector( + 'form .form-group .form-group .field-string .field-description' + ); + expect(detailsInnerHTML).to.contains('Description to renders Markdown correctly.'); + + const { innerHTML: checkboxInnerHTML } = node.querySelector( + 'form .form-group .form-group .field-boolean .field-description' + ); + expect(checkboxInnerHTML).to.contains('Checkbox with some markdown!'); + }); + it('should not render markdown in description when enableMarkdownInDescription is not present in uiSchema', () => { + const { node } = createFormComponent({ schema }); + + const { innerHTML: rootInnerHTML } = node.querySelector('form .form-group .form-group .field-description'); + expect(rootInnerHTML).to.contains('New *description*, with some Markdown.'); + + const { innerHTML: detailsInnerHTML } = node.querySelector( + 'form .form-group .form-group .field-string .field-description' + ); + expect(detailsInnerHTML).to.contains('Description to renders Markdown **correctly**.'); + + const { innerHTML: checkboxInnerHTML } = node.querySelector( + 'form .form-group .form-group .field-boolean .field-description' + ); + expect(checkboxInnerHTML).to.contains('Checkbox with some `markdown`!'); + }); + + }); }); diff --git a/packages/fluent-ui/src/DescriptionField/DescriptionField.tsx b/packages/fluent-ui/src/DescriptionField/DescriptionField.tsx index 023adb8b36..164fd88920 100644 --- a/packages/fluent-ui/src/DescriptionField/DescriptionField.tsx +++ b/packages/fluent-ui/src/DescriptionField/DescriptionField.tsx @@ -1,14 +1,18 @@ -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; import { Text } from '@fluentui/react'; export default function DescriptionField< T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any ->({ description, id }: DescriptionFieldProps) { - if (description) { - return {description}; +>({ id, description, registry, uiSchema }: DescriptionFieldProps) { + if (!description) { + return null; } - return null; + return ( + + + + ); } diff --git a/packages/fluentui-rc/src/DescriptionField/DescriptionField.tsx b/packages/fluentui-rc/src/DescriptionField/DescriptionField.tsx index 12f923704f..0f555757d3 100644 --- a/packages/fluentui-rc/src/DescriptionField/DescriptionField.tsx +++ b/packages/fluentui-rc/src/DescriptionField/DescriptionField.tsx @@ -1,5 +1,5 @@ import { Text, makeStyles, tokens } from '@fluentui/react-components'; -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; const useStyles = makeStyles({ label: { @@ -17,15 +17,15 @@ export default function DescriptionField< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any >(props: DescriptionFieldProps) { - const { id, description } = props; + const { id, description, registry, uiSchema } = props; const classes = useStyles(); - if (description) { - return ( - - {description} - - ); + if (!description) { + return null; } - return null; + return ( + + + + ); } diff --git a/packages/material-ui/src/DescriptionField/DescriptionField.tsx b/packages/material-ui/src/DescriptionField/DescriptionField.tsx index 26c0a5df35..d9bb61a182 100644 --- a/packages/material-ui/src/DescriptionField/DescriptionField.tsx +++ b/packages/material-ui/src/DescriptionField/DescriptionField.tsx @@ -1,5 +1,5 @@ import Typography from '@material-ui/core/Typography'; -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; /** The `DescriptionField` is the template to use to render the description of a field * @@ -10,11 +10,11 @@ export default function DescriptionField< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any >(props: DescriptionFieldProps) { - const { id, description } = props; + const { id, description, registry, uiSchema } = props; if (description) { return ( - {description} + ); } diff --git a/packages/mui/src/DescriptionField/DescriptionField.tsx b/packages/mui/src/DescriptionField/DescriptionField.tsx index 758548997d..5c6fdb5ecf 100644 --- a/packages/mui/src/DescriptionField/DescriptionField.tsx +++ b/packages/mui/src/DescriptionField/DescriptionField.tsx @@ -1,5 +1,5 @@ import Typography from '@mui/material/Typography'; -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; /** The `DescriptionField` is the template to use to render the description of a field * @@ -10,14 +10,14 @@ export default function DescriptionField< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any >(props: DescriptionFieldProps) { - const { id, description } = props; - if (description) { - return ( - - {description} - - ); + const { id, description, registry, uiSchema } = props; + if (!description) { + return null; } - return null; + return ( + + + + ); } diff --git a/packages/semantic-ui/src/DescriptionField/DescriptionField.tsx b/packages/semantic-ui/src/DescriptionField/DescriptionField.tsx index 581b25d5ab..c9bafd3b5c 100644 --- a/packages/semantic-ui/src/DescriptionField/DescriptionField.tsx +++ b/packages/semantic-ui/src/DescriptionField/DescriptionField.tsx @@ -1,4 +1,4 @@ -import { DescriptionFieldProps, FormContextType, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; +import { DescriptionFieldProps, FormContextType, RichDescription, RJSFSchema, StrictRJSFSchema } from '@rjsf/utils'; /** The `DescriptionField` is the template to use to render the description of a field * @@ -9,13 +9,13 @@ export default function DescriptionField< S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any >(props: DescriptionFieldProps) { - const { id, description } = props; + const { id, description, registry, uiSchema } = props; if (!description) { return null; } return (

- {description} +

); } diff --git a/packages/utils/src/components/RichDescription.tsx b/packages/utils/src/components/RichDescription.tsx new file mode 100644 index 0000000000..bf2cdd3281 --- /dev/null +++ b/packages/utils/src/components/RichDescription.tsx @@ -0,0 +1,28 @@ +import getUiOptions from '../getUiOptions'; +import { FormContextType, Registry, RJSFSchema, StrictRJSFSchema, UiSchema } from '../types'; +import Markdown from 'markdown-to-jsx'; + +interface RichDescriptionProps { + description: string; + uiSchema?: UiSchema; + registry: Registry; +} + +export default function RichDescription< + T = any, + S extends StrictRJSFSchema = RJSFSchema, + F extends FormContextType = any +>({ description, registry, uiSchema = {} }: RichDescriptionProps) { + const { globalUiOptions } = registry; + const uiOptions = getUiOptions(uiSchema, globalUiOptions); + + return ( + <> + {uiOptions.enableMarkdownInDescription ? ( + {description} + ) : ( + description + )} + + ); +} diff --git a/packages/utils/src/components/index.tsx b/packages/utils/src/components/index.tsx new file mode 100644 index 0000000000..4b31f78820 --- /dev/null +++ b/packages/utils/src/components/index.tsx @@ -0,0 +1,3 @@ +import RichDescription from './RichDescription'; + +export { RichDescription }; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index f22a69abb9..de77ebac48 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -60,6 +60,8 @@ export * from './constants'; export * from './parser'; export * from './schema'; +export * from './components'; + export { allowAdditionalItems, ariaDescribedByIds, diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts index 359d6bb45c..4e48e8c1e7 100644 --- a/packages/utils/src/types.ts +++ b/packages/utils/src/types.ts @@ -541,7 +541,7 @@ export type DescriptionFieldProps; /** The description of the field being rendered */ - description: string | ReactElement; + description: string; /** The `registry` object */ registry: Registry; }; @@ -683,7 +683,7 @@ export type ObjectFieldTemplateProps< /** A string value containing the title for the object */ title: string; /** A string value containing the description for the object */ - description?: string; + description?: ReactNode; /** A boolean value stating if the object is disabled */ disabled?: boolean; /** An array of objects representing the properties in the object */