import type { ReactNode } from 'react'; import React, { useContext, useMemo } from 'react'; import type { ButtonProps } from 'antd'; import omit from 'omit.js'; import { Button, Form, Tooltip, ConfigProvider } from 'antd'; import type { FormListFieldData, FormListOperation, FormListProps } from 'antd/lib/form/FormList'; import type { LabelTooltipType } from 'antd/lib/form/FormItemLabel'; import type { NamePath } from 'antd/lib/form/interface'; import { DeleteOutlined, PlusOutlined, CopyOutlined } from '@ant-design/icons'; import './index.less'; import get from 'rc-util/lib/utils/get'; import { runFunction } from '@ant-design/pro-utils'; type IconConfig = { Icon?: React.FC; tooltipText?: string; }; const FormListContext = React.createContext< | (FormListFieldData & { listName: NamePath; }) | Record >({}); type ChildrenFunction = ( fields: FormListFieldData[], operation: FormListOperation, meta: { errors: React.ReactNode[]; }, ) => React.ReactNode; export type ProFormListProps = Omit & { creatorButtonProps?: | false | (ButtonProps & { creatorButtonText?: ReactNode; position?: 'top' | 'bottom'; }); creatorRecord?: Record | (() => Record); label?: ReactNode; tooltip?: LabelTooltipType; actionRender?: ( field: FormListFieldData, action: FormListOperation, defaultActionDom: ReactNode[], ) => ReactNode[]; children: ReactNode | ChildrenFunction; /** 自定义Item,可以用来将 action 放到别的地方 */ itemRender?: ( doms: { listDom: ReactNode; action: ReactNode }, listMeta: { field: FormListFieldData; fields: FormListFieldData[]; operation: FormListOperation; record: Record; meta: { errors: React.ReactNode[]; }; }, ) => ReactNode; copyIconProps?: IconConfig | false; deleteIconProps?: IconConfig | false; }; const ProFormList: React.FC = ({ children, actionRender, creatorButtonProps, label, tooltip, creatorRecord, itemRender, rules, copyIconProps = { Icon: CopyOutlined, tooltipText: '复制此行', }, deleteIconProps = { Icon: DeleteOutlined, tooltipText: '删除此行', }, ...rest }) => { const context = useContext(ConfigProvider.ConfigContext); const listContext = useContext(FormListContext); const baseClassName = context.getPrefixCls('pro-form-list'); // 处理 list 的嵌套 const name = useMemo(() => { if (listContext.name === undefined) { return [rest.name].flat(1); } return [listContext.name, rest.name].flat(1); }, [listContext.name, rest.name]); return ( { return get(prevValues, name) !== get(nextValues, name); }} > {({ getFieldValue }) => { return (
{(fields, action, meta) => { const creatorButton = creatorButtonProps !== false && ( ); if (typeof children === 'function') { return (children as ChildrenFunction)(fields, action, meta); } return ( <>
{creatorButtonProps !== false && creatorButtonProps?.position === 'top' && creatorButton} {fields.map((field) => { const defaultActionDom: React.ReactNode[] = []; if (copyIconProps) { const { Icon = CopyOutlined, tooltipText } = copyIconProps as IconConfig; defaultActionDom.push( { action.add( getFieldValue( [listContext.listName, rest.name, field.name] .filter((item) => item !== undefined) .flat(1), ), ); }} /> , ); } if (deleteIconProps) { const { Icon = DeleteOutlined, tooltipText } = deleteIconProps; defaultActionDom.push( action.remove(field.name)} /> , ); } const actions = actionRender?.(field, action, defaultActionDom) || defaultActionDom; const dom = actions.length > 0 ? (
{actions}
) : null; const contentDom = itemRender?.( { listDom:
{children}
, action: dom, }, { field, record: getFieldValue( [listContext.listName, rest.name, field.name] .filter((item) => item !== undefined) .flat(1), ), fields, operation: action, meta, }, ) || (
{children}
{dom}
); return ( item !== undefined) .flat(1), }} > {contentDom} ); })} {creatorButtonProps !== false && creatorButtonProps?.position !== 'top' && creatorButton}
); }}
); }}
); }; export { FormListContext }; export default ProFormList;