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: Add generic type support to the bootstrap-4 theme #3326

Merged
merged 4 commits into from Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -25,6 +25,7 @@ should change the heading of the (upcoming) version to include a major version b
- Updated the usage of the `ButtonTemplates` to pass the new required `registry` prop, filtering it out in the actual implementations before spreading props, fixing - [#3314](https://github.com/rjsf-team/react-jsonschema-form/issues/3314)
- Updated `CheckboxWidget` to get the `required` state of the checkbox from the `schemaRequiresTrueValue()` utility function rather than the `required` prop, fixing [#3317](https://github.com/rjsf-team/react-jsonschema-form/issues/3317)
- Updated the test for the `CheckboxWidget` validating that the `schema.title` is passed as the label, fixing [#3302](https://github.com/rjsf-team/react-jsonschema-form/issues/3302)
- Updated the theme to accept generic types, exporting `generateXXX` functions for `Form`, `Theme`, `Templates` and `Widgets` to support using the theme with user-specified type generics, partially fixing [#3072](https://github.com/rjsf-team/react-jsonschema-form/issues/3072)

## @rjsf/chakra-ui
- Updated the usage of the `ButtonTemplates` to pass the new required `registry` prop, filtering it out in the actual implementations before spreading props, fixing - [#3314](https://github.com/rjsf-team/react-jsonschema-form/issues/3314)
Expand Down
39 changes: 22 additions & 17 deletions packages/bootstrap-4/src/AddButton/AddButton.tsx
@@ -1,21 +1,26 @@
import React from "react";
import { IconButtonProps } from "@rjsf/utils";
import {
FormContextType,
IconButtonProps,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";
import Button from "react-bootstrap/Button";
import { BsPlus } from "@react-icons/all-files/bs/BsPlus";

const AddButton: React.ComponentType<IconButtonProps> = ({
uiSchema,
registry,
...props
}) => (
<Button
{...props}
style={{ width: "100%" }}
className={`ml-1 ${props.className}`}
title="Add Item"
>
<BsPlus />
</Button>
);

export default AddButton;
export default function AddButton<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({ uiSchema, registry, ...props }: IconButtonProps<T, S, F>) {
return (
<Button
{...props}
style={{ width: "100%" }}
className={`ml-1 ${props.className}`}
title="Add Item"
>
<BsPlus />
</Button>
);
}
@@ -1,9 +1,18 @@
import React, { CSSProperties } from "react";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import { ArrayFieldTemplateItemType } from "@rjsf/utils";
import {
ArrayFieldTemplateItemType,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const ArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => {
export default function ArrayFieldItemTemplate<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: ArrayFieldTemplateItemType<T, S, F>) {
const {
children,
disabled,
Expand Down Expand Up @@ -75,6 +84,4 @@ const ArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => {
</Row>
</div>
);
};

export default ArrayFieldItemTemplate;
}
49 changes: 30 additions & 19 deletions packages/bootstrap-4/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx
Expand Up @@ -5,11 +5,18 @@ import Container from "react-bootstrap/Container";
import {
ArrayFieldTemplateItemType,
ArrayFieldTemplateProps,
FormContextType,
getTemplate,
getUiOptions,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
export default function ArrayFieldTemplate<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: ArrayFieldTemplateProps<T, S, F>) {
const {
canAdd,
disabled,
Expand All @@ -23,23 +30,24 @@ const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
schema,
title,
} = props;
const uiOptions = getUiOptions(uiSchema);
const ArrayFieldDescriptionTemplate =
getTemplate<"ArrayFieldDescriptionTemplate">(
"ArrayFieldDescriptionTemplate",
registry,
uiOptions
);
const ArrayFieldItemTemplate = getTemplate<"ArrayFieldItemTemplate">(
const uiOptions = getUiOptions<T, S, F>(uiSchema);
const ArrayFieldDescriptionTemplate = getTemplate<
"ArrayFieldDescriptionTemplate",
T,
S,
F
>("ArrayFieldDescriptionTemplate", registry, uiOptions);
const ArrayFieldItemTemplate = getTemplate<"ArrayFieldItemTemplate", T, S, F>(
"ArrayFieldItemTemplate",
registry,
uiOptions
);
const ArrayFieldTitleTemplate = getTemplate<"ArrayFieldTitleTemplate">(
const ArrayFieldTitleTemplate = getTemplate<
"ArrayFieldTitleTemplate",
registry,
uiOptions
);
T,
S,
F
>("ArrayFieldTitleTemplate", registry, uiOptions);
// Button templates are not overridden in the uiSchema
const {
ButtonTemplates: { AddButton },
Expand Down Expand Up @@ -69,9 +77,14 @@ const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
className="p-0 m-0"
>
{items &&
items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType) => (
<ArrayFieldItemTemplate key={key} {...itemProps} />
))}
items.map(
({
key,
...itemProps
}: ArrayFieldTemplateItemType<T, S, F>) => (
<ArrayFieldItemTemplate key={key} {...itemProps} />
)
)}
{canAdd && (
<Container className="">
<Row className="mt-2">
Expand All @@ -93,6 +106,4 @@ const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
</Row>
</div>
);
};

export default ArrayFieldTemplate;
}
25 changes: 18 additions & 7 deletions packages/bootstrap-4/src/BaseInputTemplate/BaseInputTemplate.tsx
@@ -1,8 +1,18 @@
import React from "react";
import Form from "react-bootstrap/Form";
import { getInputProps, WidgetProps } from "@rjsf/utils";
import {
FormContextType,
getInputProps,
RJSFSchema,
StrictRJSFSchema,
WidgetProps,
} from "@rjsf/utils";

const BaseInputTemplate = ({
export default function BaseInputTemplate<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({
id,
placeholder,
required,
Expand All @@ -19,8 +29,11 @@ const BaseInputTemplate = ({
rawErrors = [],
children,
extraProps,
}: WidgetProps) => {
const inputProps = { ...extraProps, ...getInputProps(schema, type, options) };
}: WidgetProps<T, S, F>) {
const inputProps = {
...extraProps,
...getInputProps<T, S, F>(schema, type, options),
};
const _onChange = ({
target: { value },
}: React.ChangeEvent<HTMLInputElement>) =>
Expand Down Expand Up @@ -62,6 +75,4 @@ const BaseInputTemplate = ({
) : null}
</>
);
};

export default BaseInputTemplate;
}
21 changes: 14 additions & 7 deletions packages/bootstrap-4/src/CheckboxWidget/CheckboxWidget.tsx
@@ -1,9 +1,18 @@
import React from "react";

import { WidgetProps, schemaRequiresTrueValue } from "@rjsf/utils";
import {
WidgetProps,
schemaRequiresTrueValue,
StrictRJSFSchema,
RJSFSchema,
FormContextType,
} from "@rjsf/utils";
import Form from "react-bootstrap/Form";

const CheckboxWidget = (props: WidgetProps) => {
export default function CheckboxWidget<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: WidgetProps<T, S, F>) {
const {
id,
value,
heath-freenome marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -19,7 +28,7 @@ const CheckboxWidget = (props: WidgetProps) => {
// Because an unchecked checkbox will cause html5 validation to fail, only add
// the "required" attribute if the field value must be "true", due to the
// "const" or "enum" keywords
const required = schemaRequiresTrueValue(schema);
const required = schemaRequiresTrueValue<S>(schema);

const _onChange = ({
target: { checked },
Expand Down Expand Up @@ -51,6 +60,4 @@ const CheckboxWidget = (props: WidgetProps) => {
/>
</Form.Group>
);
};

export default CheckboxWidget;
}
19 changes: 13 additions & 6 deletions packages/bootstrap-4/src/CheckboxesWidget/CheckboxesWidget.tsx
@@ -1,6 +1,11 @@
import React from "react";
import Form from "react-bootstrap/Form";
import { WidgetProps } from "@rjsf/utils";
import {
FormContextType,
RJSFSchema,
StrictRJSFSchema,
WidgetProps,
} from "@rjsf/utils";

const selectValue = (value: any, selected: any, all: any) => {
const at = all.indexOf(value);
Expand All @@ -15,7 +20,11 @@ const deselectValue = (value: any, selected: any) => {
return selected.filter((v: any) => v !== value);
};

const CheckboxesWidget = ({
export default function CheckboxesWidget<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({
id,
disabled,
options,
Expand All @@ -26,7 +35,7 @@ const CheckboxesWidget = ({
onChange,
onBlur,
onFocus,
}: WidgetProps) => {
}: WidgetProps<T, S, F>) {
const { enumOptions, enumDisabled, inline } = options;

const _onChange =
Expand Down Expand Up @@ -78,6 +87,4 @@ const CheckboxesWidget = ({
})}
</Form.Group>
);
};

export default CheckboxesWidget;
}
17 changes: 12 additions & 5 deletions packages/bootstrap-4/src/DescriptionField/DescriptionField.tsx
@@ -1,7 +1,16 @@
import React from "react";
import { DescriptionFieldProps } from "@rjsf/utils";
import {
DescriptionFieldProps,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const DescriptionField = ({ id, description }: DescriptionFieldProps) => {
export default function DescriptionField<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({ id, description }: DescriptionFieldProps<T, S, F>) {
if (description) {
return (
<div>
Expand All @@ -13,6 +22,4 @@ const DescriptionField = ({ id, description }: DescriptionFieldProps) => {
}

return null;
};

export default DescriptionField;
}
47 changes: 28 additions & 19 deletions packages/bootstrap-4/src/ErrorList/ErrorList.tsx
Expand Up @@ -3,23 +3,32 @@ import React from "react";
import Card from "react-bootstrap/Card";
import ListGroup from "react-bootstrap/ListGroup";

import { ErrorListProps } from "@rjsf/utils";
import {
ErrorListProps,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const ErrorList = ({ errors }: ErrorListProps) => (
<Card border="danger" className="mb-4">
<Card.Header className="alert-danger">Errors</Card.Header>
<Card.Body className="p-0">
<ListGroup>
{errors.map((error, i: number) => {
return (
<ListGroup.Item key={i} className="border-0">
<span>{error.stack}</span>
</ListGroup.Item>
);
})}
</ListGroup>
</Card.Body>
</Card>
);

export default ErrorList;
export default function ErrorList<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({ errors }: ErrorListProps<T, S, F>) {
return (
<Card border="danger" className="mb-4">
<Card.Header className="alert-danger">Errors</Card.Header>
<Card.Body className="p-0">
<ListGroup>
{errors.map((error, i: number) => {
return (
<ListGroup.Item key={i} className="border-0">
<span>{error.stack}</span>
</ListGroup.Item>
);
})}
</ListGroup>
</Card.Body>
</Card>
);
}
13 changes: 11 additions & 2 deletions packages/bootstrap-4/src/FieldErrorTemplate/FieldErrorTemplate.tsx
@@ -1,12 +1,21 @@
import React from "react";
import { FieldErrorProps } from "@rjsf/utils";
import {
FieldErrorProps,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";
import ListGroup from "react-bootstrap/ListGroup";

/** The `FieldErrorTemplate` component renders the errors local to the particular field
*
* @param props - The `FieldErrorProps` for the errors being rendered
*/
export default function FieldErrorTemplate(props: FieldErrorProps) {
export default function FieldErrorTemplate<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: FieldErrorProps<T, S, F>) {
const { errors = [], idSchema } = props;
if (errors.length === 0) {
return null;
Expand Down