Open SachinKotnala opened 10 months ago
@SachinKotnala This is a popular request that requires quite a bit of work to build in a generic manner across all themes. Are you feeling ambitious enough to try build it?
Hi @heath-freenome , I'm not a very ambitious person, but I've created this modification as a part of rjsf-team/react-jsonschema-form/packages/antd/src/templates/ObjectFieldTemplate/index.tsx
for one of my own projects.
It's a simple change, wherein I've added a ui:grid check in ui:schema. If present, it will set the column span in accordance to the element in the grid:
{uiSchema?.['ui:grid'] && Array.isArray(uiSchema['ui:grid']) ?
uiSchema['ui:grid'].map((ui_row) => {
return Object.keys(ui_row).map((row_item) => {
let element = properties.find((p => p.name == row_item))
if (element) {
return <Col key={element.name} span={ui_row[row_item]}>
{element.content}
</Col>
} else {
return <></>
}
})
})
: properties
.filter((e) => !e.hidden)
.map((element: ObjectFieldTemplatePropertyType) => (
<Col key={element.name} span={calculateColSpan(element)}>
{element.content}
</Col>
))}
Here's the complete ObjectFieldTemplate/index.tsx file - Please chip in your inputs for improvements, so if possible, will try raising a PR:
import classNames from 'classnames';
import isObject from 'lodash/isObject';
import isNumber from 'lodash/isNumber';
import isString from 'lodash/isString';
import {
FormContextType,
GenericObjectType,
ObjectFieldTemplateProps,
ObjectFieldTemplatePropertyType,
RJSFSchema,
StrictRJSFSchema,
UiSchema,
canExpand,
descriptionId,
getTemplate,
getUiOptions,
titleId,
} from '@rjsf/utils';
import Col from 'antd/lib/col';
import Row from 'antd/lib/row';
import { ConfigConsumer, ConfigConsumerProps } from 'antd/lib/config-provider/context';
const DESCRIPTION_COL_STYLE = {
paddingBottom: '8px',
};
/** The `ObjectFieldTemplate` is the template to use to render all the inner properties of an object along with the
* title and description if available. If the object is expandable, then an `AddButton` is also rendered after all
* the properties.
*
* @param props - The `ObjectFieldTemplateProps` for this component
*/
export default function ObjectFieldTemplate<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(props: ObjectFieldTemplateProps<T, S, F>) {
const {
description,
disabled,
formContext,
formData,
idSchema,
onAddClick,
properties,
readonly,
required,
registry,
schema,
title,
uiSchema,
} = props;
console.log('ObjectFieldTemplate props: ')
console.log(props)
const uiOptions = getUiOptions<T, S, F>(uiSchema);
const TitleFieldTemplate = getTemplate<'TitleFieldTemplate', T, S, F>('TitleFieldTemplate', registry, uiOptions);
const DescriptionFieldTemplate = getTemplate<'DescriptionFieldTemplate', T, S, F>(
'DescriptionFieldTemplate',
registry,
uiOptions
);
// Button templates are not overridden in the uiSchema
const {
ButtonTemplates: { AddButton },
} = registry.templates;
const { colSpan = 24, labelAlign = 'right', rowGutter = 24 } = formContext as GenericObjectType;
const findSchema = (element: ObjectFieldTemplatePropertyType): S => element.content.props.schema;
const findSchemaType = (element: ObjectFieldTemplatePropertyType) => findSchema(element).type;
const findUiSchema = (element: ObjectFieldTemplatePropertyType): UiSchema<T, S, F> | undefined =>
element.content.props.uiSchema;
const findUiSchemaField = (element: ObjectFieldTemplatePropertyType) => getUiOptions(findUiSchema(element)).field;
const findUiSchemaWidget = (element: ObjectFieldTemplatePropertyType) => getUiOptions(findUiSchema(element)).widget;
const calculateColSpan = (element: ObjectFieldTemplatePropertyType) => {
const type = findSchemaType(element);
const field = findUiSchemaField(element);
const widget = findUiSchemaWidget(element);
const defaultColSpan =
properties.length < 2 || // Single or no field in object.
type === 'object' ||
type === 'array' ||
widget === 'textarea'
? 24
: 12;
if (isObject(colSpan)) {
const colSpanObj: GenericObjectType = colSpan;
if (isString(widget)) {
return colSpanObj[widget];
}
if (isString(field)) {
return colSpanObj[field];
}
if (isString(type)) {
return colSpanObj[type];
}
}
if (isNumber(colSpan)) {
return colSpan;
}
return defaultColSpan;
};
return (
<ConfigConsumer>
{(configProps: ConfigConsumerProps) => {
console.log('config props are')
console.log(configProps)
const { getPrefixCls } = configProps;
const prefixCls = getPrefixCls('form');
const labelClsBasic = `${prefixCls}-item-label`;
const labelColClassName = classNames(
labelClsBasic,
labelAlign === 'left' && `${labelClsBasic}-left`
// labelCol.className,
);
return (
<fieldset id={idSchema.$id}>
<Row gutter={rowGutter}>
{title && (
<Col className={labelColClassName} span={24}>
<TitleFieldTemplate
id={titleId<T>(idSchema)}
title={title}
required={required}
schema={schema}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
)}
{description && (
<Col span={24} style={DESCRIPTION_COL_STYLE}>
<DescriptionFieldTemplate
id={descriptionId<T>(idSchema)}
description={description}
schema={schema}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
)}
{uiSchema?.['ui:grid'] && Array.isArray(uiSchema['ui:grid']) ?
uiSchema['ui:grid'].map((ui_row) => {
return Object.keys(ui_row).map((row_item) => {
let element = properties.find((p => p.name == row_item))
if (element) {
return <Col key={element.name} span={ui_row[row_item]}>
{element.content}
</Col>
} else {
return <></>
}
})
})
: properties
.filter((e) => !e.hidden)
.map((element: ObjectFieldTemplatePropertyType) => (
<Col key={element.name} span={calculateColSpan(element)}>
{element.content}
</Col>
))}
</Row>
{canExpand(schema, uiSchema, formData) && (
<Col span={24}>
<Row gutter={rowGutter} justify='end'>
<Col flex='192px'>
<AddButton
className='object-property-expand'
disabled={disabled || readonly}
onClick={onAddClick(schema)}
uiSchema={uiSchema}
registry={registry}
/>
</Col>
</Row>
</Col>
)}
</fieldset>
);
}}
</ConfigConsumer>
);
}
@priyank-R The main challenge to make this a standard feature in RJSF is the fact that every Theme has it own, differing, implementation of doing a grid. So to build an out-of-the-box capability is going to be quite the undertaking so that it supports all themes. You are welcome to create your own custom field implementation for your local use. I do have a ticket (#3752) in the v6 world that is aimed at creating a library of well-known, RJSF supported theming elements that would allow people build way more customizable forms. Now if only I had time from work to be able to build it.
Prerequisites
What theme are you using?
antd
Is your feature request related to a problem? Please describe.
It appears that it is not currently possible to create a multi-column form using Antd. For instance, I would like to have a login form with a firstname and lastname field positioned next to each other instead of being generated below one another by default.
What I want to achieve is this: [firstname ] [lastname ] [company] [personalemail] [workemail]
but it is [firstname ] [lastname ] [company] [personalemail] [workemail] [submit button]
Describe the solution you'd like
I think something similar to what we have for MUI will work for antd
Describe alternatives you've considered
No response