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

fix: #3104 by adding new templates #3109

Merged
merged 6 commits into from
Sep 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ jobs:
run: npm run build
env:
SHOW_NETLIFY_BADGE: true
NODE_OPTIONS: --max_old_space_size=4096
- name: Build
if: github.ref == 'refs/heads/main'
run: npm run build
env:
NODE_OPTIONS: --max_old_space_size=4096

- if: matrix.node-version == '16.x'
uses: actions/upload-artifact@v3
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ 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-beta.7

## @rjsf/core
- Added new field `ArraySchemaField`, assigned to `SchemaField` by default, that is used by the `ArrayField` to render the `children` for each array field element
- Refactored the internal `ErrorList` and `Help` components from inside of `SchemaField` to new templates: `FieldErrorTemplate` and `FieldHelpTemplate`; fixes (https://github.com/rjsf-team/react-jsonschema-form/issues/3104)

## @rjsf/utils
- Added new `FieldErrorProps` and `FieldHelpProps` types
- Added new `FieldErrorTemplate` and `FieldHelpTemplate` to the `TemplatesType`

## Dev / docs / playground
- Updated the `custom-templates.md` file to add documentation for the new `FieldErrorTemplate` and `FieldHelpTemplate`
- Updated the `custom-widgets-fields.md` file to add documentation for the new `ArraySchemaField` field.

# v5.0.0-beta.6

## @rjsf/bootstrap-4
Expand Down
81 changes: 81 additions & 0 deletions docs/advanced-customization/custom-templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ Below is the table that lists all the `templates`, their props interface, their
| [BaseInputTemplate*](#BaseInputTemplate) | WidgetProps | ui:BaseInputTemplate | Formerly a `widget` in `@rjsf.core` moved to `templates` and newly implemented in each theme to maximize code reuse. |
| [DescriptionFieldTemplate*](#DescriptionFieldTemplate) | DescriptionFieldProps | ui:DescriptionFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. Previously implemented in each theme. |
| [ErrorListTemplate*](#ErrorListTemplate) | ErrorListProps | ui:ErrorListTemplate | Formerly `Form.ErrorList` moved to `templates` with the `Templates` suffix. Previously implemented in each theme. |
| [FieldErrorTemplate](#FieldErrorTemplate) | FieldErrorProps | ui:FieldErrorTemplate | Formerly internal `ErrorList` component accessible only to `SchemaField` |
| [FieldHelpTemplate](#FieldHelpTemplate) | FieldHelpProps | ui:FieldHelpTemplate | Formerly internal `Help` component accessible only to `SchemaField` |
| [FieldTemplate](#FieldTemplate) | FieldTemplateProps | ui:FieldTemplate | Formerly `Form.FieldTemplate` or `Registry.FieldTemplate` |
| [ObjectFieldTemplate](#ObjectFieldTemplate) | ObjectFieldTemplateProps | ui:ObjectFieldTemplate | Formerly `Form.ObjectFieldTemplate` or `Registry.ObjectFieldTemplate` |
| [TitleFieldTemplate*](#TitleFieldTemplate) | TitleFieldProps | ui:TitleFieldTemplate | Formerly a `field` in `@rjsf.core` moved to `templates` with the `Template` suffix. Previously implemented in each theme. |
Expand Down Expand Up @@ -449,6 +451,85 @@ The following props are passed to the `ErrorListTemplate`:
- `errors`: An array of all errors in this `Form`.
- `errorSchema`: The `ErrorSchema` constructed by `Form`

## FieldErrorTemplate
The `FieldErrorTemplate` is the template that renders all the errors associated a single field.
If you want to customize how the errors are rendered you can.

```tsx
import { FieldErrorProps } from "@rjsf/utils";
import validator from '@rjsf/validator-ajv6';

const schema = {
type: "string",
title: "My input",
description: "input description"
};

function FieldErrorTemplate(props: FieldErrorProps) {
const { errors } = props;
return (
<details id={id}>
<summary>Errors</summary>
<ul>
{errors.map((error: string, i: number) => {
return (
<li key={i} className="error">
{error.stack}
</li>
);
})}
</ul>
</details>
);
}

render((
<Form schema={schema} validator={validator} templates={{ FieldErrorTemplate }} />
), document.getElementById("app"));
```

The following props are passed to the `FieldErrorTemplate`:

- `schema`: The schema for the field
- `uiSchema`: The uiSchema for the field
- `idSchema`: An object containing the id for this field & ids for its properties.
- `errors`: An array of all errors for this field
- `errorSchema`: The `ErrorSchema` for this field
- `registry`: The `Registry` object

## FieldHelpTemplate
The `FieldHelpTemplate` is the template that renders the help associated a single field.
If you want to customize how the help is rendered you can.

```tsx
import { FieldHelpProps } from "@rjsf/utils";
import validator from '@rjsf/validator-ajv6';

const schema = {
type: "string",
title: "My input",
description: "input description"
};

function FieldHelpTemplate(props: FieldHelpProps) {
const { help, idSchema } = props;
const id = `${idSchema.$id}__help`;
return <aside id={id}>{help}</aside>;
}

render((
<Form schema={schema} validator={validator} templates={{ FieldHelpTemplate }} />
), document.getElementById("app"));
```

The following props are passed to the `FieldHelpTemplate`:

- `schema`: The schema for the field
- `uiSchema`: The uiSchema for the field
- `idSchema`: An object containing the id for this field & ids for its properties.
- `help`: The help information to be rendered
- `registry`: The `Registry` object

## FieldTemplate

To take control over the inner organization of each field (each form row), you can define a *field template* for your form.
Expand Down
30 changes: 30 additions & 0 deletions docs/advanced-customization/custom-widgets-fields.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ function MyForm(props) {
The default fields you can override are:

- `ArrayField`
- `ArraySchemaField`
- `BooleanField`
- `DescriptionField`
- `OneOfField`
Expand Down Expand Up @@ -351,3 +352,32 @@ render((
If you're curious how this could ever be useful, have a look at the [Kinto formbuilder](https://github.com/Kinto/formbuilder) repository to see how it's used to provide editing capabilities to any form field.

Props passed to a custom SchemaField are the same as [the ones passed to a custom field](#field-props).

### Custom ArraySchemaField

Everything that was mentioned above for a `Custom SchemaField` applies, but this is only used to render the Array item `children` that are then passed to the `ArrayFieldItemTemplate`.
By default, `ArraySchemaField` uses the main `SchemaField` implementation.
If you want to customize how the individual items for an array are rendered, override the `ArraySchemaField`.

```jsx
import validator from '@rjsf/validator-ajv6';

const CustomArraySchemaField = function(props) {
const { index, registry } = props;
const { SchemaField } = registry.fields;
const name = `Index ${index}`;
return <SchemaField {...props} name={name} />;
};

const fields = {
ArraySchemaField: CustomArraySchemaField
};

const schema = {
type: "string"
};

render((
<Form schema={schema} validator={validator} fields={fields} />
), document.getElementById("app"));
```
22 changes: 21 additions & 1 deletion packages/antd/test/Form.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,27 @@ describe("single fields", () => {
examples: ["Firefox", "Chrome", "Opera", "Vivaldi", "Safari"],
};
const tree = renderer
.create(<Form schema={schema} validator={validator} tagName="div" />)
.create(<Form schema={schema} validator={validator} />)
.toJSON();
expect(tree).toMatchSnapshot();
});
test("help and error display", () => {
const schema = {
type: "string",
};
const uiSchema = {
"ui:help": "help me!",
};
const extraErrors = { __errors: ["an error"] };
const tree = renderer
.create(
<Form
schema={schema}
uiSchema={uiSchema}
validator={validator}
extraErrors={extraErrors}
/>
)
.toJSON();
expect(tree).toMatchSnapshot();
});
Expand Down
122 changes: 120 additions & 2 deletions packages/antd/test/__snapshots__/Form.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,124 @@ exports[`single fields format datetime 1`] = `
</form>
`;

exports[`single fields help and error display 1`] = `
<form
className="rjsf"
noValidate={false}
onSubmit={[Function]}
>
<div
className="ant-alert ant-alert-error ant-alert-with-description ant-alert-no-icon panel panel-danger errors"
data-show={true}
role="alert"
style={Object {}}
>
<div
className="ant-alert-content"
>
<div
className="ant-alert-message"
>
Errors
</div>
<div
className="ant-alert-description"
>
<div
className="ant-list ant-list-sm ant-list-split list-group"
>
<div
className="ant-spin-nested-loading"
>
<div
className="ant-spin-container"
>
<li
className="ant-list-item"
>
<div
className="ant-space ant-space-horizontal ant-space-align-center"
style={Object {}}
>
<div
className="ant-space-item"
style={
Object {
"marginRight": 8,
}
}
>
<span
aria-label="exclamation-circle"
className="anticon anticon-exclamation-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="exclamation-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
/>
<path
d="M464 688a48 48 0 1096 0 48 48 0 10-96 0zm24-112h48c4.4 0 8-3.6 8-8V296c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8z"
/>
</svg>
</span>
</div>
<div
className="ant-space-item"
style={Object {}}
>
. an error
</div>
</div>
</li>
</div>
</div>
</div>
</div>
</div>
</div>
<div
className="form-group field field-string field-error has-error has-danger"
>
<input
className="ant-input"
id="root"
name="root"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder=""
style={
Object {
"width": "100%",
}
}
type="text"
value=""
/>
</div>
<button
className="ant-btn ant-btn-submit"
disabled={false}
onClick={[Function]}
type="submit"
>
<span>
Submit
</span>
</button>
</form>
`;

exports[`single fields hidden field 1`] = `
<form
className="rjsf"
Expand Down Expand Up @@ -1213,7 +1331,7 @@ exports[`single fields radio field 1`] = `
`;

exports[`single fields schema examples 1`] = `
<div
<form
className="rjsf"
noValidate={false}
onSubmit={[Function]}
Expand Down Expand Up @@ -1269,7 +1387,7 @@ exports[`single fields schema examples 1`] = `
Submit
</span>
</button>
</div>
</form>
`;

exports[`single fields select field 1`] = `
Expand Down
24 changes: 22 additions & 2 deletions packages/bootstrap-4/test/Form.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { RJSFSchema, UiSchema } from "@rjsf/utils";
import { RJSFSchema, UiSchema, ErrorSchema } from "@rjsf/utils";
import validator from "@rjsf/validator-ajv6";
import renderer from "react-test-renderer";

Expand Down Expand Up @@ -365,7 +365,27 @@ describe("single fields", () => {
examples: ["Firefox", "Chrome", "Opera", "Vivaldi", "Safari"],
};
const tree = renderer
.create(<Form schema={schema} validator={validator} tagName="div" />)
.create(<Form schema={schema} validator={validator} />)
.toJSON();
expect(tree).toMatchSnapshot();
});
test("help and error display", () => {
const schema: RJSFSchema = {
type: "string",
};
const uiSchema: UiSchema = {
"ui:help": "help me!",
};
const extraErrors: ErrorSchema = { __errors: ["an error"] } as ErrorSchema;
const tree = renderer
.create(
<Form
schema={schema}
uiSchema={uiSchema}
validator={validator}
extraErrors={extraErrors}
/>
)
.toJSON();
expect(tree).toMatchSnapshot();
});
Expand Down