Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Markdown in descriptions #4405

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`

Comment on lines +30 to +33
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The package change is so small as to not require mentioning. What does want to be mentioned is that it is a new feature so requires 5.25.0 AND you want to mention the changes in each package.

# 5.23.1

## @rjsf/chakra-ui
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
10 changes: 7 additions & 3 deletions packages/antd/src/templates/DescriptionField/index.tsx
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -9,9 +9,13 @@ export default function DescriptionField<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: DescriptionFieldProps<T, S, F>) {
const { id, description } = props;
const { id, description, registry, uiSchema } = props;
if (!description) {
return null;
}
return <span id={id}>{description}</span>;
return (
<span id={id}>
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</span>
);
}
22 changes: 11 additions & 11 deletions packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx
Original file line number Diff line number Diff line change
@@ -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<T, S, F>) {
if (description) {
return (
<div>
<div id={id} className='mb-3'>
{description}
</div>
</div>
);
>({ id, description, registry, uiSchema }: DescriptionFieldProps<T, S, F>) {
if (!description) {
return null;
}

return null;
return (
<div>
<div id={id} className='mb-3'>
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</div>
</div>
);
}
18 changes: 7 additions & 11 deletions packages/chakra-ui/src/DescriptionField/DescriptionField.tsx
Original file line number Diff line number Diff line change
@@ -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<T, S, F>) {
>({ id, description, registry, uiSchema }: DescriptionFieldProps<T, S, F>) {
if (!description) {
return null;
}

if (typeof description === 'string') {
return (
<Text as='sup' fontSize='md' id={id}>
{description}
</Text>
);
}

return <>{description}</>;
return (
<Text as='sup' fontSize='md' id={id}>
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</Text>
);
}
8 changes: 1 addition & 7 deletions packages/core/src/components/fields/SchemaField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 } = {
Expand Down Expand Up @@ -201,11 +200,6 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e

const description = uiOptions.description || props.schema.description || schema.description || '';

const richDescription = uiOptions.enableMarkdownInDescription ? (
<Markdown options={{ disableParsingRawHTML: true }}>{description}</Markdown>
) : (
description
);
const help = uiOptions.help;
const hidden = uiOptions.widget === 'hidden';

Expand Down Expand Up @@ -254,7 +248,7 @@ function SchemaFieldRender<T = any, S extends StrictRJSFSchema = RJSFSchema, F e
description: (
<DescriptionFieldTemplate
id={descriptionId<T>(id)}
description={richDescription}
description={description}
schema={schema}
uiSchema={uiSchema}
registry={registry}
Expand Down
22 changes: 7 additions & 15 deletions packages/core/src/components/templates/DescriptionField.tsx
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -9,21 +9,13 @@ export default function DescriptionField<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: DescriptionFieldProps<T, S, F>) {
const { id, description } = props;
const { id, description, registry, uiSchema } = props;
if (!description) {
return null;
}
if (typeof description === 'string') {
return (
<p id={id} className='field-description'>
{description}
</p>
);
} else {
return (
<div id={id} className='field-description'>
{description}
</div>
);
}
return (
<div id={id} className='field-description'>
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</div>
);
}
72 changes: 72 additions & 0 deletions packages/core/test/ObjectField.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <em>description</em>, 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 <strong>correctly</strong>.');

const { innerHTML: checkboxInnerHTML } = node.querySelector(
'form .form-group .form-group .field-boolean .field-description'
);
expect(checkboxInnerHTML).to.contains('Checkbox with some <code>markdown</code>!');
});
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`!');
});

});
});
14 changes: 9 additions & 5 deletions packages/fluent-ui/src/DescriptionField/DescriptionField.tsx
Original file line number Diff line number Diff line change
@@ -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<T, S, F>) {
if (description) {
return <Text id={id}>{description}</Text>;
>({ id, description, registry, uiSchema }: DescriptionFieldProps<T, S, F>) {
if (!description) {
return null;
}

return null;
return (
<Text id={id}>
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</Text>
);
}
18 changes: 9 additions & 9 deletions packages/fluentui-rc/src/DescriptionField/DescriptionField.tsx
Original file line number Diff line number Diff line change
@@ -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: {
Expand All @@ -17,15 +17,15 @@ export default function DescriptionField<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: DescriptionFieldProps<T, S, F>) {
const { id, description } = props;
const { id, description, registry, uiSchema } = props;
const classes = useStyles();
if (description) {
return (
<Text block id={id} className={classes.label}>
{description}
</Text>
);
if (!description) {
return null;
}

return null;
return (
<Text block id={id} className={classes.label}>
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</Text>
);
}
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -10,11 +10,11 @@ export default function DescriptionField<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: DescriptionFieldProps<T, S, F>) {
const { id, description } = props;
const { id, description, registry, uiSchema } = props;
if (description) {
return (
<Typography id={id} variant='subtitle2' style={{ marginTop: '5px' }}>
{description}
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</Typography>
);
}
Expand Down
18 changes: 9 additions & 9 deletions packages/mui/src/DescriptionField/DescriptionField.tsx
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -10,14 +10,14 @@ export default function DescriptionField<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: DescriptionFieldProps<T, S, F>) {
const { id, description } = props;
if (description) {
return (
<Typography id={id} variant='subtitle2' style={{ marginTop: '5px' }}>
{description}
</Typography>
);
const { id, description, registry, uiSchema } = props;
if (!description) {
return null;
}

return null;
return (
<Typography id={id} variant='subtitle2' style={{ marginTop: '5px' }}>
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</Typography>
);
}
Original file line number Diff line number Diff line change
@@ -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
*
Expand All @@ -9,13 +9,13 @@ export default function DescriptionField<
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: DescriptionFieldProps<T, S, F>) {
const { id, description } = props;
const { id, description, registry, uiSchema } = props;
if (!description) {
return null;
}
return (
<p id={id} className='sui-description'>
{description}
<RichDescription description={description} registry={registry} uiSchema={uiSchema} />
</p>
);
}
Loading
Loading