mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-28 05:05:48 +08:00
fix: form item support comment (#41771)
* fix: form item support comment * chore: clean up * fix: lint
This commit is contained in:
parent
0991bf3fe9
commit
e2606d477d
@ -6,18 +6,19 @@ import type { Meta, NamePath } from 'rc-field-form/lib/interface';
|
||||
import useState from 'rc-util/lib/hooks/useState';
|
||||
import { supportRef } from 'rc-util/lib/ref';
|
||||
import * as React from 'react';
|
||||
import useFormItemStatus from '../hooks/useFormItemStatus';
|
||||
import { ConfigContext } from '../../config-provider';
|
||||
import { cloneElement, isValidElement } from '../../_util/reactNode';
|
||||
import warning from '../../_util/warning';
|
||||
import { FormContext, NoStyleItemContext } from '../context';
|
||||
import { ConfigContext } from '../../config-provider';
|
||||
import type { FormItemInputProps } from '../FormItemInput';
|
||||
import type { FormItemLabelProps, LabelTooltipType } from '../FormItemLabel';
|
||||
import { FormContext, NoStyleItemContext } from '../context';
|
||||
import useFormItemStatus from '../hooks/useFormItemStatus';
|
||||
import useFrameState from '../hooks/useFrameState';
|
||||
import useItemRef from '../hooks/useItemRef';
|
||||
import { getFieldId, toArray } from '../util';
|
||||
import ItemHolder from './ItemHolder';
|
||||
|
||||
import useChildren from '../hooks/useChildren';
|
||||
import useStyle from '../style';
|
||||
|
||||
const NAME_SPLIT = '__SPLIT__';
|
||||
@ -110,7 +111,10 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
||||
} = props;
|
||||
const { getPrefixCls } = React.useContext(ConfigContext);
|
||||
const { name: formName } = React.useContext(FormContext);
|
||||
const isRenderProps = typeof children === 'function';
|
||||
|
||||
const mergedChildren = useChildren(children);
|
||||
|
||||
const isRenderProps = typeof mergedChildren === 'function';
|
||||
const notifyParentMetaChange = React.useContext(NoStyleItemContext);
|
||||
|
||||
const { validateTrigger: contextValidateTrigger } = React.useContext(FieldContext);
|
||||
@ -232,7 +236,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
||||
}
|
||||
|
||||
if (!hasName && !isRenderProps && !dependencies) {
|
||||
return wrapSSR(renderLayout(children) as JSX.Element);
|
||||
return wrapSSR(renderLayout(mergedChildren) as JSX.Element);
|
||||
}
|
||||
|
||||
let variables: Record<string, string> = {};
|
||||
@ -287,13 +291,13 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
||||
'Form.Item',
|
||||
"`shouldUpdate` and `dependencies` shouldn't be used together. See https://u.ant.design/form-deps.",
|
||||
);
|
||||
if (Array.isArray(children) && hasName) {
|
||||
if (Array.isArray(mergedChildren) && hasName) {
|
||||
warning(
|
||||
false,
|
||||
'Form.Item',
|
||||
'A `Form.Item` with a `name` prop must have a single child element. For information on how to render more complex form items, see https://u.ant.design/complex-form-item.',
|
||||
);
|
||||
childNode = children;
|
||||
childNode = mergedChildren;
|
||||
} else if (isRenderProps && (!(shouldUpdate || dependencies) || hasName)) {
|
||||
warning(
|
||||
!!(shouldUpdate || dependencies),
|
||||
@ -311,14 +315,14 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
||||
'Form.Item',
|
||||
'Must set `name` or use a render function when `dependencies` is set.',
|
||||
);
|
||||
} else if (isValidElement(children)) {
|
||||
} else if (isValidElement(mergedChildren)) {
|
||||
warning(
|
||||
children.props.defaultValue === undefined,
|
||||
mergedChildren.props.defaultValue === undefined,
|
||||
'Form.Item',
|
||||
'`defaultValue` will not work on controlled Field. You should use `initialValues` of Form instead.',
|
||||
);
|
||||
|
||||
const childProps = { ...children.props, ...mergedControl };
|
||||
const childProps = { ...mergedChildren.props, ...mergedControl };
|
||||
if (!childProps.id) {
|
||||
childProps.id = fieldId;
|
||||
}
|
||||
@ -342,8 +346,8 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
||||
childProps['aria-required'] = 'true';
|
||||
}
|
||||
|
||||
if (supportRef(children)) {
|
||||
childProps.ref = getItemRef(mergedName, children);
|
||||
if (supportRef(mergedChildren)) {
|
||||
childProps.ref = getItemRef(mergedName, mergedChildren);
|
||||
}
|
||||
|
||||
// We should keep user origin event handler
|
||||
@ -355,7 +359,7 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
||||
triggers.forEach((eventName) => {
|
||||
childProps[eventName] = (...args: any[]) => {
|
||||
mergedControl[eventName]?.(...args);
|
||||
children.props[eventName]?.(...args);
|
||||
mergedChildren.props[eventName]?.(...args);
|
||||
};
|
||||
});
|
||||
|
||||
@ -369,21 +373,21 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
|
||||
childNode = (
|
||||
<MemoInput
|
||||
value={mergedControl[props.valuePropName || 'value']}
|
||||
update={children}
|
||||
update={mergedChildren}
|
||||
childProps={watchingChildProps}
|
||||
>
|
||||
{cloneElement(children, childProps)}
|
||||
{cloneElement(mergedChildren, childProps)}
|
||||
</MemoInput>
|
||||
);
|
||||
} else if (isRenderProps && (shouldUpdate || dependencies) && !hasName) {
|
||||
childNode = children(context);
|
||||
childNode = mergedChildren(context);
|
||||
} else {
|
||||
warning(
|
||||
!mergedName.length,
|
||||
'Form.Item',
|
||||
'`name` is only used for validate React element. If you are using Form.Item as layout display, please remove `name` instead.',
|
||||
);
|
||||
childNode = children as React.ReactNode;
|
||||
childNode = mergedChildren as React.ReactNode;
|
||||
}
|
||||
|
||||
return renderLayout(childNode, fieldId, isRequired);
|
||||
|
@ -8,6 +8,7 @@ import Form from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { fireEvent, pureRender, render, screen, waitFakeTimer } from '../../../tests/utils';
|
||||
import { resetWarned } from '../../_util/warning';
|
||||
import Button from '../../button';
|
||||
import Cascader from '../../cascader';
|
||||
import Checkbox from '../../checkbox';
|
||||
@ -1459,7 +1460,7 @@ describe('Form', () => {
|
||||
render(
|
||||
<Modal open>
|
||||
<Form>
|
||||
<Form.Item help='This is a help message'>
|
||||
<Form.Item help="This is a help message">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
@ -1547,7 +1548,7 @@ describe('Form', () => {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
return (
|
||||
<Form form={form} name='test-form'>
|
||||
<Form form={form} name="test-form">
|
||||
<Form.Item name="error" rules={[{ required: true, message: 'This is a error message.' }]}>
|
||||
<ErrorItem />
|
||||
</Form.Item>
|
||||
@ -1859,4 +1860,22 @@ describe('Form', () => {
|
||||
expect(container.querySelectorAll('.ant-form-item-required')).toHaveLength(2);
|
||||
expect(container.querySelectorAll('.ant-form-item-required-mark-optional')).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('children support comment', () => {
|
||||
resetWarned();
|
||||
|
||||
const { container } = render(
|
||||
<Form initialValues={{ name: 'bamboo', age: '14' }}>
|
||||
<Form.Item name="name">
|
||||
{/* Comment here */}
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item name="age">{[null, <Input key="input" />]}</Form.Item>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
expect(container.querySelectorAll('input')[0].value).toEqual('bamboo');
|
||||
expect(container.querySelectorAll('input')[1].value).toEqual('14');
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
13
components/form/hooks/useChildren.ts
Normal file
13
components/form/hooks/useChildren.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import toArray from 'rc-util/lib/Children/toArray';
|
||||
import type { FormItemProps } from '../FormItem';
|
||||
|
||||
export default function useChildren(
|
||||
children?: FormItemProps['children'],
|
||||
): FormItemProps['children'] {
|
||||
if (typeof children === 'function') {
|
||||
return children;
|
||||
}
|
||||
|
||||
const childList = toArray(children);
|
||||
return childList.length <= 1 ? childList[0] : childList;
|
||||
}
|
Loading…
Reference in New Issue
Block a user