feat(FormBuilder): 支持Col和FormList行的样式及标题自定义
- 为FormItem增加colStyle属性,支持内联样式及函数动态计算 - 为FormItem增加colTitle属性,支持Col内部、Form.Item之间标题节点动态渲染 - 为FormList增加rowStyle属性,支持每行内联样式及基于字段动态计算 - 为FormList增加rowTitle属性,支持每行起始位置自定义标题节点及动态渲染 - FormItemsRenderer组件新增获取样式和标题的辅助函数,支持函数和静态配置 - 渲染时合并colStyle样式并插入colTitle标题节点 - FormList的每行Row增加rowStyle样式和rowTitle标题节点渲染 - 修正Select组件showSearch属性的写法,提升可用性 - 优化Form.Item内容器的flex样式,防止布局异常1.0
parent
fcfa539fc5
commit
9527fec783
|
|
@ -3,7 +3,7 @@ import type { FormItemProps, Rule } from "antd/es/form";
|
|||
import type { FormListFieldData } from "antd/es/form/FormList";
|
||||
import type { Gutter } from "antd/es/grid/row";
|
||||
import type { NamePath } from "rc-field-form/lib/interface";
|
||||
import type { ReactElement, ReactNode } from "react";
|
||||
import type { CSSProperties, ReactElement, ReactNode } from "react";
|
||||
import type { FORM_ITEM_RENDER_TYPE_MAP } from "../../enum/formItemRender";
|
||||
import type { DeepPartial } from "./FormBuilder";
|
||||
|
||||
|
|
@ -131,6 +131,10 @@ export interface FormOptionBase<
|
|||
dependencies?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, Dependencies[]>;
|
||||
/** 是否仅用于保存标签,不渲染到页面上,只在表单中保存数据,默认 false */
|
||||
onlyForLabel?: IsOnlyForLabel;
|
||||
/** Col 的内联样式,会合并到 Col 的 style 上,支持函数动态计算 */
|
||||
colStyle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, CSSProperties | ((formValues: AllValues) => CSSProperties)>;
|
||||
/** Col 内部、Form.Item 之前渲染的标题节点,支持函数动态计算 */
|
||||
colTitle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, ReactNode | ((formValues: AllValues) => ReactNode)>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -157,6 +161,10 @@ export type FormOptionByRender<
|
|||
checkboxCol?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "checkbox" ? number : never>;
|
||||
/** Form.List 独有的属性 */
|
||||
formListUniqueProps?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "formList" ? FormListUniqueProps | ((formValues: AllValues) => FormListUniqueProps) : never>;
|
||||
/** FormList 每行的内联样式,仅 render 为 formList 时可用,支持函数按行计算 */
|
||||
rowStyle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "formList" ? CSSProperties | ((field: FormListFieldData, fieldIndex: number) => CSSProperties) : never>;
|
||||
/** FormList 每行起始位置渲染的标题节点,仅 render 为 formList 时可用,支持函数按行计算 */
|
||||
rowTitle?: FormOptionProperty<IsOnlyForLabel, IsCustomizeRender, RenderType extends "formList" ? ReactNode | ((field: FormListFieldData, fieldIndex: number) => ReactNode) : never>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -223,6 +223,34 @@ const FormItemsRenderer = ({
|
|||
return { span: itemSpan, labelCol: itemLabelCol, wrapperCol: itemWrapperCol };
|
||||
};
|
||||
|
||||
// 获取 col 样式
|
||||
const getColStyle = (option) => {
|
||||
return typeof option.colStyle === "function"
|
||||
? option.colStyle(getFormValues())
|
||||
: option.colStyle;
|
||||
};
|
||||
|
||||
// 获取 col 标题(Col 内部、Form.Item 之后)
|
||||
const getColTitle = (option) => {
|
||||
return typeof option.colTitle === "function"
|
||||
? option.colTitle(getFormValues())
|
||||
: option.colTitle;
|
||||
};
|
||||
|
||||
// 获取 row 样式(FormList 的每一行)
|
||||
const getRowStyle = (option, field, fieldIndex) => {
|
||||
return typeof option.rowStyle === "function"
|
||||
? option.rowStyle(field, fieldIndex)
|
||||
: option.rowStyle;
|
||||
};
|
||||
|
||||
// 获取 row 标题(FormList 每行末尾)
|
||||
const getRowTitle = (option, field, fieldIndex) => {
|
||||
return typeof option.rowTitle === "function"
|
||||
? option.rowTitle(field, fieldIndex)
|
||||
: option.rowTitle;
|
||||
};
|
||||
|
||||
// 获取是否动态表单项
|
||||
const getIsDynamicFormItem = (option, formItemProps) => {
|
||||
return (option.shouldUpdate ?? option.dependencies) || (formItemProps.shouldUpdate ?? formItemProps.dependencies);
|
||||
|
|
@ -274,7 +302,7 @@ const FormItemsRenderer = ({
|
|||
|
||||
case FORM_ITEM_RENDER_ENUM.SELECT:
|
||||
return (
|
||||
<Select placeholder={placeholder} showSearch allowClear optionFilterProp="children" {...componentProps}>
|
||||
<Select placeholder={placeholder} showSearch={{ optionFilterProp: "children" }} allowClear {...componentProps}>
|
||||
{(option.items || []).map((item) => {
|
||||
const { value, label, disabled } = getSelectableItemAttributes(item, itemsFieldKey);
|
||||
return (
|
||||
|
|
@ -434,7 +462,8 @@ const FormItemsRenderer = ({
|
|||
return null;
|
||||
|
||||
return (
|
||||
<Col key={getKey(option) || index} span={col.span} style={style}>
|
||||
<Col key={getKey(option) || index} span={col.span} style={{ ...style, ...getColStyle(option) }}>
|
||||
{getColTitle(option)}
|
||||
<Form.Item
|
||||
name={option.name}
|
||||
label={renderLabel(option)}
|
||||
|
|
@ -516,14 +545,18 @@ const FormItemsRenderer = ({
|
|||
const componentProps = getComponentProps(option);
|
||||
|
||||
return (
|
||||
<Col key={getKey(option) || index} span={col.span} style={style}>
|
||||
<Col key={getKey(option) || index} span={col.span} style={{ ...style, ...getColStyle(option) }}>
|
||||
{getColTitle(option)}
|
||||
<Form.List name={option.name} {...componentProps}>
|
||||
{(fields, { add, remove, move }) => (
|
||||
<>
|
||||
{fields.map((field, fieldIndex) => {
|
||||
const listOptions = getListOptions(formListUniqueProps.options, field, fieldIndex, add, remove, move);
|
||||
const rowStyle = getRowStyle(option, field, fieldIndex);
|
||||
const rowTitle = getRowTitle(option, field, fieldIndex);
|
||||
return (
|
||||
<Row gutter={gutter} key={field.key}>
|
||||
<Row gutter={gutter} key={field.key} style={rowStyle}>
|
||||
{rowTitle}
|
||||
{listOptions.map((listOption, listIndex) => {
|
||||
const col = getCol(listOption);
|
||||
const formItemProps = getFormItemProps(listOption);
|
||||
|
|
@ -574,7 +607,8 @@ const FormItemsRenderer = ({
|
|||
delete formItemProps.shouldUpdate;
|
||||
|
||||
return (
|
||||
<Col key={getKey(listOption) || listIndex} span={col.span} style={style}>
|
||||
<Col key={getKey(listOption) || listIndex} span={col.span} style={{ ...style, ...getColStyle(listOption) }}>
|
||||
{getColTitle(listOption)}
|
||||
<Form.Item
|
||||
label={renderLabel(listOption)}
|
||||
labelCol={col.labelCol}
|
||||
|
|
@ -585,7 +619,7 @@ const FormItemsRenderer = ({
|
|||
{...formItemProps}
|
||||
>
|
||||
<div style={{ display: "flex", gap: 10, alignItems: "center", justifyContent: "space-between" }}>
|
||||
<div style={{ flex: 1 }}>
|
||||
<div style={{ flex: 1, minWidth: 0 }}>
|
||||
<Form.Item
|
||||
noStyle
|
||||
rules={getRules(listOption)}
|
||||
|
|
|
|||
Loading…
Reference in New Issue