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 mui theme #3319

Merged
merged 2 commits into from Dec 29, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -36,6 +36,7 @@ should change the heading of the (upcoming) version to include a major version b
- Also, passed `registry` into the `SubmitButton` inside of the `Form` as part of this fix
- Updated `ArrayField` to pass the new `totalItems` prop to the `ArrayFieldItemTemplate` instances, fixing [#3315](https://github.com/rjsf-team/react-jsonschema-form/issues/3315)
- Also refactored the near duplicate logic for `onAddClick` and `onAddIndexClick` into a new `_handleAddClick()` function, fixing [#3316](https://github.com/rjsf-team/react-jsonschema-form/issues/3316)
- Fix passing of generic types to a few helper methods, partially fixing [#3072](https://github.com/rjsf-team/react-jsonschema-form/issues/3072)

## @rjsf/fluent-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 All @@ -48,6 +49,7 @@ should change the heading of the (upcoming) version to include a major version b
## @rjsf/mui
- 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 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/semantic-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
2 changes: 1 addition & 1 deletion docs/5.x upgrade guide.md
Expand Up @@ -24,7 +24,7 @@ Unfortunately, there is required work pending to properly support React 18, so u

### New packages

There are three new packages added in RJSF version 5:
There are four new packages added in RJSF version 5:

- `@rjsf/utils`: All of the [utility functions](https://react-jsonschema-form.readthedocs.io/en/stable/api-reference/utiltity-functions) previously imported from `@rjsf/core/utils` as well as the Typescript types for RJSF version 5.
- The following new utility functions were added: `createSchemaUtils()`, `getInputProps()`, `mergeValidationData()` and `processSelectValue()`
Expand Down
Expand Up @@ -18,7 +18,7 @@ export default function SubmitButton<
submitText,
norender,
props: submitButtonProps = {},
} = getSubmitButtonOptions(uiSchema);
} = getSubmitButtonOptions<T, S, F>(uiSchema);
if (norender) {
return null;
}
Expand Down
Expand Up @@ -73,7 +73,7 @@ export default function ObjectFieldTemplate<
/>
)}
{properties.map((prop: ObjectFieldTemplatePropertyType) => prop.content)}
{canExpand(schema, uiSchema, formData) && (
{canExpand<T, S, F>(schema, uiSchema, formData) && (
<AddButton
className="object-property-expand"
onClick={onAddClick(schema)}
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/components/widgets/CheckboxWidget.tsx
Expand Up @@ -41,7 +41,7 @@ function CheckboxWidget<
// 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 handleChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) =>
Expand Down
9 changes: 6 additions & 3 deletions packages/core/src/components/widgets/SelectWidget.tsx
Expand Up @@ -50,23 +50,26 @@ function SelectWidget<
const handleFocus = useCallback(
(event: FocusEvent<HTMLSelectElement>) => {
const newValue = getValue(event, multiple);
return onFocus(id, processSelectValue(schema, newValue, options));
return onFocus(
id,
processSelectValue<T, S, F>(schema, newValue, options)
);
},
[onFocus, id, schema, multiple, options]
);

const handleBlur = useCallback(
(event: FocusEvent<HTMLSelectElement>) => {
const newValue = getValue(event, multiple);
return onBlur(id, processSelectValue(schema, newValue, options));
return onBlur(id, processSelectValue<T, S, F>(schema, newValue, options));
},
[onBlur, id, schema, multiple, options]
);

const handleChange = useCallback(
(event: ChangeEvent<HTMLSelectElement>) => {
const newValue = getValue(event, multiple);
return onChange(processSelectValue(schema, newValue, options));
return onChange(processSelectValue<T, S, F>(schema, newValue, options));
},
[onChange, schema, multiple, options]
);
Expand Down
23 changes: 14 additions & 9 deletions packages/mui/src/AddButton/AddButton.tsx
@@ -1,18 +1,23 @@
import React from "react";
import AddIcon from "@mui/icons-material/Add";
import IconButton from "@mui/material/IconButton";
import { IconButtonProps } from "@rjsf/utils";
import {
FormContextType,
IconButtonProps,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const AddButton: React.ComponentType<IconButtonProps> = ({
uiSchema,
registry,
...props
}) => {
/** The `AddButton` renders a button that represent the `Add` action on a form
*/
export default function AddButton<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>({ uiSchema, registry, ...props }: IconButtonProps<T, S, F>) {
return (
<IconButton title="Add Item" {...props} color="primary">
<AddIcon />
</IconButton>
);
};

export default AddButton;
}
21 changes: 16 additions & 5 deletions packages/mui/src/ArrayFieldItemTemplate/ArrayFieldItemTemplate.tsx
Expand Up @@ -2,9 +2,22 @@ import React, { CSSProperties } from "react";
import Box from "@mui/material/Box";
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import { ArrayFieldTemplateItemType } from "@rjsf/utils";
import {
ArrayFieldTemplateItemType,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const ArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => {
/** The `ArrayFieldItemTemplate` component is the template used to render an items of an array.
*
* @param props - The `ArrayFieldTemplateItemType` props for the component
*/
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 @@ -70,6 +83,4 @@ const ArrayFieldItemTemplate = (props: ArrayFieldTemplateItemType) => {
)}
</Grid>
);
};

export default ArrayFieldItemTemplate;
}
54 changes: 33 additions & 21 deletions packages/mui/src/ArrayFieldTemplate/ArrayFieldTemplate.tsx
Expand Up @@ -3,13 +3,24 @@ import Box from "@mui/material/Box";
import Grid from "@mui/material/Grid";
import Paper from "@mui/material/Paper";
import {
ArrayFieldTemplateItemType,
ArrayFieldTemplateProps,
getTemplate,
getUiOptions,
ArrayFieldTemplateProps,
ArrayFieldTemplateItemType,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
/** The `ArrayFieldTemplate` component is the template used to render all items in an array.
*
* @param props - The `ArrayFieldTemplateItemType` props for the component
*/
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 +34,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 All @@ -64,9 +76,11 @@ const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
/>
<Grid container={true} key={`array-item-list-${idSchema.$id}`}>
{items &&
items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType) => (
<ArrayFieldItemTemplate key={key} {...itemProps} />
))}
items.map(
({ key, ...itemProps }: ArrayFieldTemplateItemType<T, S, F>) => (
<ArrayFieldItemTemplate key={key} {...itemProps} />
)
)}
{canAdd && (
<Grid container justifyContent="flex-end">
<Grid item={true}>
Expand All @@ -86,6 +100,4 @@ const ArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
</Box>
</Paper>
);
};

export default ArrayFieldTemplate;
}
67 changes: 41 additions & 26 deletions packages/mui/src/BaseInputTemplate/BaseInputTemplate.tsx
@@ -1,29 +1,46 @@
import React from "react";
import TextField, { TextFieldProps } from "@mui/material/TextField";
import { getInputProps, WidgetProps } from "@rjsf/utils";
import {
getInputProps,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
WidgetProps,
} from "@rjsf/utils";

const BaseInputTemplate = ({
id,
placeholder,
required,
readonly,
disabled,
type,
label,
value,
onChange,
onBlur,
onFocus,
autofocus,
options,
schema,
uiSchema,
rawErrors = [],
formContext,
registry,
...textFieldProps
}: WidgetProps) => {
const inputProps = getInputProps(schema, type, options);
/** The `BaseInputTemplate` is the template to use to render the basic `<input>` component for the `core` theme.
* It is used as the template for rendering many of the <input> based widgets that differ by `type` and callbacks only.
* It can be customized/overridden for other themes or individual implementations as needed.
*
* @param props - The `WidgetProps` for this template
*/
export default function BaseInputTemplate<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: WidgetProps<T, S, F>) {
const {
id,
placeholder,
required,
readonly,
disabled,
type,
label,
value,
onChange,
onBlur,
onFocus,
autofocus,
options,
schema,
uiSchema,
rawErrors = [],
formContext,
registry,
...textFieldProps
} = props;
const inputProps = getInputProps<T, S, F>(schema, type, options);
// Now we need to pull out the step, min, max into an inner `inputProps` for material-ui
const { step, min, max, ...rest } = inputProps;
const otherProps = {
Expand Down Expand Up @@ -77,6 +94,4 @@ const BaseInputTemplate = ({
)}
</>
);
};

export default BaseInputTemplate;
}
25 changes: 19 additions & 6 deletions packages/mui/src/CheckboxWidget/CheckboxWidget.tsx
@@ -1,9 +1,24 @@
import React from "react";
import Checkbox from "@mui/material/Checkbox";
import FormControlLabel from "@mui/material/FormControlLabel";
import { schemaRequiresTrueValue, WidgetProps } from "@rjsf/utils";
import {
schemaRequiresTrueValue,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
WidgetProps,
} from "@rjsf/utils";

const CheckboxWidget = (props: WidgetProps) => {
/** The `CheckBoxWidget` is a widget for rendering boolean properties.
* It is typically used to represent a boolean.
*
* @param props - The `WidgetProps` for this component
*/
export default function CheckboxWidget<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: WidgetProps<T, S, F>) {
const {
schema,
id,
Expand All @@ -19,7 +34,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 = (_: any, checked: boolean) => onChange(checked);
const _onBlur = ({
Expand Down Expand Up @@ -47,6 +62,4 @@ const CheckboxWidget = (props: WidgetProps) => {
label={label || ""}
/>
);
};

export default CheckboxWidget;
}