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 antd theme #3338

Merged
merged 2 commits into from Jan 4, 2023
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 @@ -20,6 +20,8 @@ should change the heading of the (upcoming) version to include a major version b
## @rjsf/antd
- 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)
- Updated the use of the deprecated `withConfigConsumer` with the `ConfigConsumer` component instead, fixing [#3336](https://github.com/rjsf-team/react-jsonschema-form/issues/3336)

## @rjsf/bootstrap-4
- 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
34 changes: 26 additions & 8 deletions packages/antd/src/index.ts
@@ -1,15 +1,33 @@
import { ComponentType } from "react";
import { FormContextType, RJSFSchema, StrictRJSFSchema } from "@rjsf/utils";
import { FormProps, ThemeProps, withTheme } from "@rjsf/core";

import Templates from "./templates";
import Widgets from "./widgets";
import Templates, { generateTemplates } from "./templates";
import Widgets, { generateWidgets } from "./widgets";

export { Templates, Widgets };
export function generateTheme<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(): ThemeProps<T, S, F> {
return {
templates: generateTemplates<T, S, F>(),
widgets: generateWidgets<T, S, F>(),
};
}

export const Theme: ThemeProps = {
templates: Templates,
widgets: Widgets,
};
const Theme = generateTheme();

export const Form: React.ComponentType<FormProps> = withTheme(Theme);
export function generateForm<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(): ComponentType<FormProps<T, S, F>> {
return withTheme<T, S, F>(generateTheme<T, S, F>());
}

const Form = generateForm();

export { Form, Templates, Theme, Widgets, generateTemplates, generateWidgets };

export default Form;
48 changes: 30 additions & 18 deletions packages/antd/src/templates/ArrayFieldItemTemplate/index.tsx
@@ -1,8 +1,13 @@
import React from "react";
import { ArrayFieldTemplateItemType } from "@rjsf/utils";
import Button from "antd/lib/button";
import Col from "antd/lib/col";
import Row from "antd/lib/row";
import {
ArrayFieldTemplateItemType,
FormContextType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";

const BTN_GRP_STYLE = {
width: "100%",
Expand All @@ -12,20 +17,29 @@ const BTN_STYLE = {
width: "calc(100% / 3)",
};

const ArrayFieldItemTemplate = ({
children,
disabled,
hasMoveDown,
hasMoveUp,
hasRemove,
hasToolbar,
index,
onDropIndexClick,
onReorderClick,
readonly,
registry,
uiSchema,
}: 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,
hasMoveDown,
hasMoveUp,
hasRemove,
hasToolbar,
index,
onDropIndexClick,
onReorderClick,
readonly,
registry,
uiSchema,
} = props;
const { MoveDownButton, MoveUpButton, RemoveButton } =
registry.templates.ButtonTemplates;
const { rowGutter = 24, toolbarAlign = "top" } = registry.formContext;
Expand Down Expand Up @@ -69,6 +83,4 @@ const ArrayFieldItemTemplate = ({
)}
</Row>
);
};

export default ArrayFieldItemTemplate;
}
207 changes: 116 additions & 91 deletions packages/antd/src/templates/ArrayFieldTemplate/index.tsx
Expand Up @@ -3,119 +3,144 @@ import {
getTemplate,
getUiOptions,
ArrayFieldTemplateProps,
ArrayFieldTemplateItemType,
FormContextType,
GenericObjectType,
RJSFSchema,
StrictRJSFSchema,
} from "@rjsf/utils";
import classNames from "classnames";
import Col from "antd/lib/col";
import Row from "antd/lib/row";
import { withConfigConsumer } from "antd/lib/config-provider/context";
import {
ConfigConsumer,
ConfigConsumerProps,
} from "antd/lib/config-provider/context";

const DESCRIPTION_COL_STYLE = {
paddingBottom: "8px",
};

// Add in the `prefixCls` element needed by the `withConfigConsumer` HOC
export type AntdArrayFieldTemplateProps = ArrayFieldTemplateProps & {
prefixCls: string;
};

const ArrayFieldTemplate = ({
canAdd,
className,
disabled,
formContext,
idSchema,
items,
onAddClick,
prefixCls,
readonly,
registry,
required,
schema,
title,
uiSchema,
}: AntdArrayFieldTemplateProps) => {
const uiOptions = getUiOptions(uiSchema);
const ArrayFieldDescriptionTemplate = getTemplate(
"ArrayFieldDescriptionTemplate",
/** 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,
className,
disabled,
formContext,
idSchema,
items,
onAddClick,
readonly,
registry,
uiOptions
);
const ArrayFieldItemTemplate = getTemplate<"ArrayFieldItemTemplate">(
required,
schema,
title,
uiSchema,
} = props;
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 },
} = registry.templates;
const { labelAlign = "right", rowGutter = 24 } = formContext;

const labelClsBasic = `${prefixCls}-item-label`;
const labelColClassName = classNames(
labelClsBasic,
labelAlign === "left" && `${labelClsBasic}-left`
// labelCol.className,
);
const { labelAlign = "right", rowGutter = 24 } =
formContext as GenericObjectType;

return (
<fieldset className={className} id={idSchema.$id}>
<Row gutter={rowGutter}>
{(uiOptions.title || title) && (
<Col className={labelColClassName} span={24}>
<ArrayFieldTitleTemplate
idSchema={idSchema}
required={required}
title={uiOptions.title || title}
schema={schema}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
)}
{(uiOptions.description || schema.description) && (
<Col span={24} style={DESCRIPTION_COL_STYLE}>
<ArrayFieldDescriptionTemplate
description={uiOptions.description || schema.description || ""}
idSchema={idSchema}
schema={schema}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
)}
<Col className="row array-item-list" span={24}>
{items &&
items.map(({ key, ...itemProps }) => (
<ArrayFieldItemTemplate key={key} {...itemProps} />
))}
</Col>
<ConfigConsumer>
{(configProps: ConfigConsumerProps) => {
const { getPrefixCls } = configProps;
const prefixCls = getPrefixCls("form");
const labelClsBasic = `${prefixCls}-item-label`;
const labelColClassName = classNames(
labelClsBasic,
labelAlign === "left" && `${labelClsBasic}-left`
// labelCol.className,
);

{canAdd && (
<Col span={24}>
<Row gutter={rowGutter} justify="end">
<Col flex="192px">
<AddButton
className="array-item-add"
disabled={disabled || readonly}
onClick={onAddClick}
uiSchema={uiSchema}
registry={registry}
/>
return (
<fieldset className={className} id={idSchema.$id}>
<Row gutter={rowGutter}>
{(uiOptions.title || title) && (
<Col className={labelColClassName} span={24}>
<ArrayFieldTitleTemplate
idSchema={idSchema}
required={required}
title={uiOptions.title || title}
schema={schema}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
)}
{(uiOptions.description || schema.description) && (
<Col span={24} style={DESCRIPTION_COL_STYLE}>
<ArrayFieldDescriptionTemplate
description={
uiOptions.description || schema.description || ""
}
idSchema={idSchema}
schema={schema}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
)}
<Col className="row array-item-list" span={24}>
{items &&
items.map(
({
key,
...itemProps
}: ArrayFieldTemplateItemType<T, S, F>) => (
<ArrayFieldItemTemplate key={key} {...itemProps} />
)
)}
</Col>

{canAdd && (
<Col span={24}>
<Row gutter={rowGutter} justify="end">
<Col flex="192px">
<AddButton
className="array-item-add"
disabled={disabled || readonly}
onClick={onAddClick}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
</Row>
</Col>
)}
</Row>
</Col>
)}
</Row>
</fieldset>
</fieldset>
);
}}
</ConfigConsumer>
);
};

export default withConfigConsumer<AntdArrayFieldTemplateProps>({
prefixCls: "form",
})(ArrayFieldTemplate);
}