mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-18 06:03:38 +08:00
feat: ConfigProvider add form requiredMark (#27322)
* feat: ConfigProvider add form requiredMark * Update Form.tsx
This commit is contained in:
parent
b4c67402e6
commit
7e782daec0
@ -0,0 +1,247 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`ConfigProvider.Form form requiredMark set requiredMark optional 1`] = `
|
||||
<ConfigProvider
|
||||
form={
|
||||
Object {
|
||||
"requiredMark": "optional",
|
||||
}
|
||||
}
|
||||
>
|
||||
<LocaleReceiver
|
||||
componentName="global"
|
||||
>
|
||||
<SizeContextProvider>
|
||||
<LocaleProvider
|
||||
_ANT_MARK__="internalMark"
|
||||
locale={Object {}}
|
||||
>
|
||||
<ForwardRef(InternalForm)
|
||||
initialValues={
|
||||
Object {
|
||||
"age": 18,
|
||||
}
|
||||
}
|
||||
>
|
||||
<SizeContextProvider>
|
||||
<ForwardRef(Form)
|
||||
className="ant-form ant-form-horizontal"
|
||||
form={
|
||||
Object {
|
||||
"__INTERNAL__": Object {
|
||||
"itemRef": [Function],
|
||||
"name": undefined,
|
||||
},
|
||||
"getFieldError": [Function],
|
||||
"getFieldInstance": [Function],
|
||||
"getFieldValue": [Function],
|
||||
"getFieldsError": [Function],
|
||||
"getFieldsValue": [Function],
|
||||
"getInternalHooks": [Function],
|
||||
"isFieldTouched": [Function],
|
||||
"isFieldValidating": [Function],
|
||||
"isFieldsTouched": [Function],
|
||||
"isFieldsValidating": [Function],
|
||||
"resetFields": [Function],
|
||||
"scrollToField": [Function],
|
||||
"setFields": [Function],
|
||||
"setFieldsValue": [Function],
|
||||
"submit": [Function],
|
||||
"validateFields": [Function],
|
||||
}
|
||||
}
|
||||
initialValues={
|
||||
Object {
|
||||
"age": 18,
|
||||
}
|
||||
}
|
||||
onFinishFailed={[Function]}
|
||||
>
|
||||
<form
|
||||
className="ant-form ant-form-horizontal"
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<FormItem
|
||||
label="年龄"
|
||||
name="age"
|
||||
rules={
|
||||
Array [
|
||||
Object {
|
||||
"len": 17,
|
||||
"type": "number",
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<WrapperField
|
||||
label="年龄"
|
||||
messageVariables={
|
||||
Object {
|
||||
"label": "年龄",
|
||||
}
|
||||
}
|
||||
name="age"
|
||||
onReset={[Function]}
|
||||
rules={
|
||||
Array [
|
||||
Object {
|
||||
"len": 17,
|
||||
"type": "number",
|
||||
},
|
||||
]
|
||||
}
|
||||
trigger="onChange"
|
||||
validateTrigger="onChange"
|
||||
>
|
||||
<Field
|
||||
key="_age"
|
||||
label="年龄"
|
||||
messageVariables={
|
||||
Object {
|
||||
"label": "年龄",
|
||||
}
|
||||
}
|
||||
name={
|
||||
Array [
|
||||
"age",
|
||||
]
|
||||
}
|
||||
onReset={[Function]}
|
||||
rules={
|
||||
Array [
|
||||
Object {
|
||||
"len": 17,
|
||||
"type": "number",
|
||||
},
|
||||
]
|
||||
}
|
||||
trigger="onChange"
|
||||
validateTrigger="onChange"
|
||||
valuePropName="value"
|
||||
>
|
||||
<Row
|
||||
className="ant-form-item"
|
||||
key="row"
|
||||
>
|
||||
<div
|
||||
className="ant-row ant-form-item"
|
||||
style={Object {}}
|
||||
>
|
||||
<FormItemLabel
|
||||
htmlFor="age"
|
||||
label="年龄"
|
||||
name="age"
|
||||
prefixCls="ant-form"
|
||||
required={false}
|
||||
requiredMark="optional"
|
||||
rules={
|
||||
Array [
|
||||
Object {
|
||||
"len": 17,
|
||||
"type": "number",
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<Col
|
||||
className="ant-form-item-label"
|
||||
>
|
||||
<div
|
||||
className="ant-col ant-form-item-label"
|
||||
style={Object {}}
|
||||
>
|
||||
<label
|
||||
className="ant-form-item-required-mark-optional"
|
||||
htmlFor="age"
|
||||
title="年龄"
|
||||
>
|
||||
年龄
|
||||
<span
|
||||
className="ant-form-item-optional"
|
||||
>
|
||||
(optional)
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</Col>
|
||||
</FormItemLabel>
|
||||
<FormItemInput
|
||||
errors={Array []}
|
||||
label="年龄"
|
||||
name={
|
||||
Array [
|
||||
"age",
|
||||
]
|
||||
}
|
||||
onDomErrorVisibleChange={[Function]}
|
||||
prefixCls="ant-form"
|
||||
rules={
|
||||
Array [
|
||||
Object {
|
||||
"len": 17,
|
||||
"type": "number",
|
||||
},
|
||||
]
|
||||
}
|
||||
status=""
|
||||
touched={false}
|
||||
validateStatus=""
|
||||
validating={false}
|
||||
>
|
||||
<Col
|
||||
className="ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
className="ant-col ant-form-item-control"
|
||||
style={Object {}}
|
||||
>
|
||||
<div
|
||||
className="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
className="ant-form-item-control-input-content"
|
||||
>
|
||||
<Component
|
||||
update={1}
|
||||
value={18}
|
||||
>
|
||||
<input
|
||||
id="age"
|
||||
onChange={[Function]}
|
||||
value={18}
|
||||
/>
|
||||
</Component>
|
||||
</div>
|
||||
</div>
|
||||
<ErrorList
|
||||
errors={Array []}
|
||||
onDomErrorVisibleChange={[Function]}
|
||||
>
|
||||
<CSSMotion
|
||||
motionAppear={true}
|
||||
motionDeadline={500}
|
||||
motionName="show-help"
|
||||
onLeaveEnd={[Function]}
|
||||
removeOnLeave={true}
|
||||
visible={false}
|
||||
>
|
||||
<DomWrapper />
|
||||
</CSSMotion>
|
||||
</ErrorList>
|
||||
</div>
|
||||
</Col>
|
||||
</FormItemInput>
|
||||
</div>
|
||||
</Row>
|
||||
</Field>
|
||||
</WrapperField>
|
||||
</FormItem>
|
||||
</form>
|
||||
</ForwardRef(Form)>
|
||||
</SizeContextProvider>
|
||||
</ForwardRef(InternalForm)>
|
||||
</LocaleProvider>
|
||||
</SizeContextProvider>
|
||||
</LocaleReceiver>
|
||||
</ConfigProvider>
|
||||
`;
|
@ -5,7 +5,7 @@ import ConfigProvider from '..';
|
||||
import zhCN from '../../locale/zh_CN';
|
||||
import Form from '../../form';
|
||||
|
||||
describe('ConfigProvider.Form.Locale', () => {
|
||||
describe('ConfigProvider.Form', () => {
|
||||
describe('form validateMessages', () => {
|
||||
const wrapperComponent = ({ validateMessages }) => {
|
||||
const formRef = React.createRef();
|
||||
@ -75,4 +75,20 @@ describe('ConfigProvider.Form.Locale', () => {
|
||||
expect(wrapper.find('.ant-form-item-explain').last().text()).toEqual('年龄必须等于17');
|
||||
});
|
||||
});
|
||||
|
||||
describe('form requiredMark', () => {
|
||||
it('set requiredMark optional', async () => {
|
||||
const wrapper = mount(
|
||||
<ConfigProvider form={{ requiredMark: 'optional' }}>
|
||||
<Form initialValues={{ age: 18 }}>
|
||||
<Form.Item name="age" label="年龄" rules={[{ type: 'number', len: 17 }]}>
|
||||
<input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
@ -2,6 +2,7 @@ import * as React from 'react';
|
||||
import defaultRenderEmpty, { RenderEmptyHandler } from './renderEmpty';
|
||||
import { Locale } from '../locale-provider';
|
||||
import { SizeType } from './SizeContext';
|
||||
import { RequiredMark } from '../form/Form';
|
||||
|
||||
export interface CSPConfig {
|
||||
nonce?: string;
|
||||
@ -28,6 +29,9 @@ export interface ConfigConsumerProps {
|
||||
};
|
||||
virtual?: boolean;
|
||||
dropdownMatchSelectWidth?: boolean;
|
||||
form?: {
|
||||
requiredMark?: RequiredMark;
|
||||
};
|
||||
}
|
||||
|
||||
export const ConfigContext = React.createContext<ConfigConsumerProps>({
|
||||
|
@ -43,7 +43,7 @@ Some components use dynamic style to support wave effect. You can config `csp` p
|
||||
| csp | Set [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) config | { nonce: string } | - | |
|
||||
| direction | Set direction of layout. See [demo](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
|
||||
| dropdownMatchSelectWidth | Determine whether the dropdown menu and the select input are the same width. Default set `min-width` same as input. Will ignore when value less than select width. `false` will disable virtual scroll | boolean \| number | - | 4.3.0 |
|
||||
| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validateMessages) } | - | |
|
||||
| form | Set Form common props | { validateMessages?: [ValidateMessages](/components/form/#validateMessages), requiredMark?: boolean \| `optional` } | - | requiredMark: 4.8.0 |
|
||||
| getPopupContainer | To set the container of the popup element. The default is to create a `div` element in `body` | function(triggerNode) | () => document.body | |
|
||||
| getTargetContainer | Config Affix, Anchor scroll target container | () => HTMLElement | () => window | 4.2.0 |
|
||||
| input | Set Input common props | { autoComplete?: string } | - | 4.2.0 |
|
||||
|
@ -11,6 +11,7 @@ import { ConfigConsumer, ConfigContext, CSPConfig, ConfigConsumerProps } from '.
|
||||
import { SizeType, SizeContextProvider } from './SizeContext';
|
||||
import message from '../message';
|
||||
import notification from '../notification';
|
||||
import { RequiredMark } from '../form/Form';
|
||||
|
||||
export { RenderEmptyHandler, ConfigContext, ConfigConsumer, CSPConfig, ConfigConsumerProps };
|
||||
|
||||
@ -36,6 +37,7 @@ export interface ConfigProviderProps {
|
||||
autoInsertSpaceInButton?: boolean;
|
||||
form?: {
|
||||
validateMessages?: ValidateMessages;
|
||||
requiredMark?: RequiredMark;
|
||||
};
|
||||
input?: {
|
||||
autoComplete?: string;
|
||||
@ -130,8 +132,11 @@ const ConfigProvider: React.FC<ConfigProviderProps> & {
|
||||
config.input = input;
|
||||
}
|
||||
|
||||
let childNode = children;
|
||||
if (form) {
|
||||
config.form = form;
|
||||
}
|
||||
|
||||
let childNode = children;
|
||||
// Additional Form provider
|
||||
let validateMessages: ValidateMessages = {};
|
||||
|
||||
|
@ -44,7 +44,7 @@ export default () => (
|
||||
| csp | 设置 [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) 配置 | { nonce: string } | - | |
|
||||
| direction | 设置文本展示方向。 [示例](#components-config-provider-demo-direction) | `ltr` \| `rtl` | `ltr` | |
|
||||
| dropdownMatchSelectWidth | 下拉菜单和选择器同宽。默认将设置 `min-width`,当值小于选择框宽度时会被忽略。`false` 时会关闭虚拟滚动 | boolean \| number | - | 4.3.0 |
|
||||
| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form/#validateMessages) } | - | |
|
||||
| form | 设置 Form 组件的通用属性 | { validateMessages?: [ValidateMessages](/components/form/#validateMessages), requiredMark?: boolean \| `optional` } | - | requiredMark: 4.8.0 |
|
||||
| getPopupContainer | 弹出框(Select, Tooltip, Menu 等等)渲染父节点,默认渲染到 body 上。 | function(triggerNode) | () => document.body | |
|
||||
| getTargetContainer | 配置 Affix、Anchor 滚动监听容器。 | () => HTMLElement | () => window | 4.2.0 |
|
||||
| input | 设置 Input 组件的通用属性 | { autoComplete?: string } | - | 4.2.0 |
|
||||
|
@ -5,7 +5,7 @@ import FieldForm, { List } from 'rc-field-form';
|
||||
import { FormProps as RcFormProps } from 'rc-field-form/lib/Form';
|
||||
import { ValidateErrorEntity } from 'rc-field-form/lib/interface';
|
||||
import { ColProps } from '../grid/col';
|
||||
import { ConfigContext, ConfigConsumerProps } from '../config-provider';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { FormContext, FormContextProps } from './context';
|
||||
import { FormLabelAlign } from './interface';
|
||||
import useForm, { FormInstance } from './hooks/useForm';
|
||||
@ -32,7 +32,7 @@ export interface FormProps<Values = any> extends Omit<RcFormProps<Values>, 'form
|
||||
|
||||
const InternalForm: React.ForwardRefRenderFunction<unknown, FormProps> = (props, ref) => {
|
||||
const contextSize = React.useContext(SizeContext);
|
||||
const { getPrefixCls, direction }: ConfigConsumerProps = React.useContext(ConfigContext);
|
||||
const { getPrefixCls, direction, form: contextForm } = React.useContext(ConfigContext);
|
||||
|
||||
const { name } = props;
|
||||
|
||||
@ -58,12 +58,16 @@ const InternalForm: React.ForwardRefRenderFunction<unknown, FormProps> = (props,
|
||||
return requiredMark;
|
||||
}
|
||||
|
||||
if (contextForm && contextForm.requiredMark !== undefined) {
|
||||
return contextForm.requiredMark;
|
||||
}
|
||||
|
||||
if (hideRequiredMark) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}, [hideRequiredMark, requiredMark]);
|
||||
}, [hideRequiredMark, requiredMark, contextForm]);
|
||||
|
||||
const prefixCls = getPrefixCls('form', customizePrefixCls);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user