mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
feat: custom feedback icons (#43894)
* custom feedback icons initial
(cherry picked from commit 22e43ad0357ea5294baf6eda659c900b1ab170f1)
* tests added and snaps updated
* Revert "tests added and snaps updated"
This reverts commit 13b57be30c
.
* unittest and documentation changes
* feedback items could be turn off
* documentation fix
* move feedback icons object into the hasFeedback prop
* feedbackIcons added to the form element
* test: commit trigger
* fix: failed form test
* snaps updated
* Update components/form/index.en-US.md
Co-authored-by: afc163 <afc163@gmail.com>
Signed-off-by: Gunay <gladio@gmail.com>
* Update components/form/index.en-US.md
Co-authored-by: afc163 <afc163@gmail.com>
Signed-off-by: Gunay <gladio@gmail.com>
* Update components/form/index.zh-CN.md
Co-authored-by: afc163 <afc163@gmail.com>
Signed-off-by: Gunay <gladio@gmail.com>
* Update components/form/demo/custom-feedback-icons.md
Signed-off-by: afc163 <afc163@gmail.com>
* Update components/form/demo/custom-feedback-icons.md
Signed-off-by: afc163 <afc163@gmail.com>
---------
Signed-off-by: Gunay <gladio@gmail.com>
Signed-off-by: afc163 <afc163@gmail.com>
Co-authored-by: afc163 <afc163@gmail.com>
This commit is contained in:
parent
4c91896abb
commit
46341b115c
@ -18,6 +18,7 @@ import useFormWarning from './hooks/useFormWarning';
|
||||
import type { FormLabelAlign } from './interface';
|
||||
import useStyle from './style';
|
||||
import ValidateMessagesContext from './validateMessagesContext';
|
||||
import type { FeedbackIcons } from './FormItem';
|
||||
|
||||
export type RequiredMark =
|
||||
| boolean
|
||||
@ -35,6 +36,7 @@ export interface FormProps<Values = any> extends Omit<RcFormProps<Values>, 'form
|
||||
labelCol?: ColProps;
|
||||
wrapperCol?: ColProps;
|
||||
form?: FormInstance<Values>;
|
||||
feedbackIcons?: FeedbackIcons;
|
||||
size?: SizeType;
|
||||
disabled?: boolean;
|
||||
scrollToFirstError?: Options | boolean;
|
||||
@ -67,6 +69,7 @@ const InternalForm: React.ForwardRefRenderFunction<FormInstance, FormProps> = (p
|
||||
onFinishFailed,
|
||||
name,
|
||||
style,
|
||||
feedbackIcons,
|
||||
...restFormProps
|
||||
} = props;
|
||||
|
||||
@ -132,8 +135,19 @@ const InternalForm: React.ForwardRefRenderFunction<FormInstance, FormProps> = (p
|
||||
requiredMark: mergedRequiredMark,
|
||||
itemRef: __INTERNAL__.itemRef,
|
||||
form: wrapForm,
|
||||
feedbackIcons,
|
||||
}),
|
||||
[name, labelAlign, labelCol, wrapperCol, layout, mergedColon, mergedRequiredMark, wrapForm],
|
||||
[
|
||||
name,
|
||||
labelAlign,
|
||||
labelCol,
|
||||
wrapperCol,
|
||||
layout,
|
||||
mergedColon,
|
||||
mergedRequiredMark,
|
||||
wrapForm,
|
||||
feedbackIcons,
|
||||
],
|
||||
);
|
||||
|
||||
React.useImperativeHandle(ref, () => wrapForm);
|
||||
|
@ -59,7 +59,7 @@ export default function ItemHolder(props: ItemHolderProps) {
|
||||
} = props;
|
||||
|
||||
const itemPrefixCls = `${prefixCls}-item`;
|
||||
const { requiredMark } = React.useContext(FormContext);
|
||||
const { requiredMark, feedbackIcons } = React.useContext(FormContext);
|
||||
|
||||
// ======================== Margin ========================
|
||||
const itemRef = React.useRef<HTMLDivElement>(null);
|
||||
@ -111,24 +111,29 @@ export default function ItemHolder(props: ItemHolderProps) {
|
||||
const formItemStatusContext = React.useMemo<FormItemStatusContextProps>(() => {
|
||||
let feedbackIcon: React.ReactNode;
|
||||
if (hasFeedback) {
|
||||
const customIcons = (hasFeedback !== true && hasFeedback.icons) || feedbackIcons;
|
||||
const customIconNode =
|
||||
mergedValidateStatus &&
|
||||
customIcons?.({ status: mergedValidateStatus, errors, warnings })?.[mergedValidateStatus];
|
||||
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
|
||||
feedbackIcon = IconNode ? (
|
||||
<span
|
||||
className={classNames(
|
||||
`${itemPrefixCls}-feedback-icon`,
|
||||
`${itemPrefixCls}-feedback-icon-${mergedValidateStatus}`,
|
||||
)}
|
||||
>
|
||||
<IconNode />
|
||||
</span>
|
||||
) : null;
|
||||
feedbackIcon =
|
||||
customIconNode !== false && IconNode ? (
|
||||
<span
|
||||
className={classNames(
|
||||
`${itemPrefixCls}-feedback-icon`,
|
||||
`${itemPrefixCls}-feedback-icon-${mergedValidateStatus}`,
|
||||
)}
|
||||
>
|
||||
{customIconNode || <IconNode />}
|
||||
</span>
|
||||
) : null;
|
||||
}
|
||||
|
||||
return {
|
||||
status: mergedValidateStatus,
|
||||
errors,
|
||||
warnings,
|
||||
hasFeedback,
|
||||
hasFeedback: !!hasFeedback,
|
||||
feedbackIcon,
|
||||
isFormItemInput: true,
|
||||
};
|
||||
|
@ -34,6 +34,12 @@ type RenderChildren<Values = any> = (form: FormInstance<Values>) => React.ReactN
|
||||
type RcFieldProps<Values = any> = Omit<FieldProps<Values>, 'children'>;
|
||||
type ChildrenType<Values = any> = RenderChildren<Values> | React.ReactNode;
|
||||
|
||||
export type FeedbackIcons = (itemStatus: {
|
||||
status: ValidateStatus;
|
||||
errors?: React.ReactNode[];
|
||||
warnings?: React.ReactNode[];
|
||||
}) => { [key in ValidateStatus]?: React.ReactNode };
|
||||
|
||||
interface MemoInputProps {
|
||||
value: any;
|
||||
update: any;
|
||||
@ -61,7 +67,7 @@ export interface FormItemProps<Values = any>
|
||||
rootClassName?: string;
|
||||
children?: ChildrenType<Values>;
|
||||
id?: string;
|
||||
hasFeedback?: boolean;
|
||||
hasFeedback?: boolean | { icons: FeedbackIcons };
|
||||
validateStatus?: ValidateStatus;
|
||||
required?: boolean;
|
||||
hidden?: boolean;
|
||||
|
@ -2215,6 +2215,177 @@ exports[`renders components/form/demo/control-ref.tsx extend context correctly 1
|
||||
|
||||
exports[`renders components/form/demo/control-ref.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/form/demo/custom-feedback-icons.tsx extend context correctly 1`] = `
|
||||
<form
|
||||
class="ant-form ant-form-horizontal"
|
||||
id="custom-feedback-icons"
|
||||
style="max-width: 600px;"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item acss-140b0ev ant-form-item-with-help"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item-row"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label"
|
||||
>
|
||||
<label
|
||||
class="ant-form-item-required"
|
||||
for="custom-feedback-icons_custom-feedback-test-item"
|
||||
title="Test"
|
||||
>
|
||||
Test
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
aria-required="true"
|
||||
class="ant-input"
|
||||
id="custom-feedback-icons_custom-feedback-test-item"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="display: flex; flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-show-help-appear ant-form-show-help-appear-start ant-form-show-help ant-form-item-explain-connected"
|
||||
id="custom-feedback-icons_custom-feedback-test-item_help"
|
||||
role="alert"
|
||||
>
|
||||
<div
|
||||
class="ant-form-show-help-item-appear ant-form-show-help-item-appear-start ant-form-show-help-item"
|
||||
style="height: 0px; opacity: 0;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="width: 0px; height: 24px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-margin-offset"
|
||||
style="margin-bottom: -24px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item acss-140b0ev ant-form-item-with-help"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item-row"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label"
|
||||
>
|
||||
<label
|
||||
class="ant-form-item-required"
|
||||
for="custom-feedback-icons_custom-feedback-test-item2"
|
||||
title="Test"
|
||||
>
|
||||
Test
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
aria-required="true"
|
||||
class="ant-input"
|
||||
id="custom-feedback-icons_custom-feedback-test-item2"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style="display: flex; flex-wrap: nowrap;"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-show-help-appear ant-form-show-help-appear-start ant-form-show-help ant-form-item-explain-connected"
|
||||
id="custom-feedback-icons_custom-feedback-test-item2_help"
|
||||
role="alert"
|
||||
>
|
||||
<div
|
||||
class="ant-form-show-help-item-appear ant-form-show-help-item-appear-start ant-form-show-help-item"
|
||||
style="height: 0px; opacity: 0;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="width: 0px; height: 24px;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-margin-offset"
|
||||
style="margin-bottom: -24px;"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item-row"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`renders components/form/demo/custom-feedback-icons.tsx extend context correctly 2`] = `[]`;
|
||||
|
||||
exports[`renders components/form/demo/customized-form-controls.tsx extend context correctly 1`] = `
|
||||
<form
|
||||
class="ant-form ant-form-inline"
|
||||
|
@ -1641,6 +1641,133 @@ exports[`renders components/form/demo/control-ref.tsx correctly 1`] = `
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`renders components/form/demo/custom-feedback-icons.tsx correctly 1`] = `
|
||||
<form
|
||||
class="ant-form ant-form-horizontal"
|
||||
id="custom-feedback-icons"
|
||||
style="max-width:600px"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item acss-140b0ev ant-form-item-with-help"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item-row"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label"
|
||||
>
|
||||
<label
|
||||
class="ant-form-item-required"
|
||||
for="custom-feedback-icons_custom-feedback-test-item"
|
||||
title="Test"
|
||||
>
|
||||
Test
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
aria-required="true"
|
||||
class="ant-input"
|
||||
id="custom-feedback-icons_custom-feedback-test-item"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item acss-140b0ev ant-form-item-with-help"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item-row"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label"
|
||||
>
|
||||
<label
|
||||
class="ant-form-item-required"
|
||||
for="custom-feedback-icons_custom-feedback-test-item2"
|
||||
title="Test"
|
||||
>
|
||||
Test
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
aria-required="true"
|
||||
class="ant-input"
|
||||
id="custom-feedback-icons_custom-feedback-test-item2"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item"
|
||||
>
|
||||
<div
|
||||
class="ant-row ant-form-item-row"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-control"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<button
|
||||
class="ant-btn ant-btn-default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
Submit
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`renders components/form/demo/customized-form-controls.tsx correctly 1`] = `
|
||||
<form
|
||||
class="ant-form ant-form-inline"
|
||||
|
@ -2,6 +2,7 @@ import classNames from 'classnames';
|
||||
import type { ChangeEventHandler } from 'react';
|
||||
import React, { version as ReactVersion, useEffect, useRef, useState } from 'react';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
import { AlertFilled } from '@ant-design/icons';
|
||||
import type { ColProps } from 'antd/es/grid';
|
||||
import type { FormInstance } from '..';
|
||||
import Form from '..';
|
||||
@ -1239,7 +1240,6 @@ describe('Form', () => {
|
||||
expect((Util.getFieldId as () => string)()).toBe(itemName);
|
||||
|
||||
// make sure input id is parentNode
|
||||
expect(screen.getByLabelText(itemName)).toHaveAttribute('id', itemName);
|
||||
expect(screen.getByLabelText(itemName)).toHaveAccessibleName('Search');
|
||||
|
||||
fireEvent.click(container.querySelector('button')!);
|
||||
@ -1781,6 +1781,66 @@ describe('Form', () => {
|
||||
expect(container.querySelector('.ant-form-item-has-error')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('custom feedback icons should display when pass hasFeedback prop', async () => {
|
||||
const App = ({ trigger = false }: { trigger?: boolean }) => {
|
||||
const form = useRef<FormInstance<any>>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!trigger) return;
|
||||
form.current?.validateFields();
|
||||
}, [trigger]);
|
||||
|
||||
return (
|
||||
<Form
|
||||
ref={form}
|
||||
feedbackIcons={() => ({
|
||||
error: <AlertFilled id="custom-error-icon" />,
|
||||
})}
|
||||
>
|
||||
<Form.Item
|
||||
label="Success"
|
||||
name="name1"
|
||||
hasFeedback
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input your value',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Success"
|
||||
name="name1"
|
||||
hasFeedback={{
|
||||
icons: () => ({
|
||||
error: <AlertFilled id="custom-error-icon2" />,
|
||||
}),
|
||||
}}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input your value 3',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
const { container, rerender } = render(<App />);
|
||||
|
||||
expect(container.querySelectorAll('.ant-form-item-has-feedback').length).toBe(0);
|
||||
|
||||
rerender(<App trigger />);
|
||||
await waitFakeTimer();
|
||||
|
||||
expect(container.querySelectorAll('.ant-form-item-has-feedback').length).toBe(2);
|
||||
expect(container.querySelectorAll('#custom-error-icon, #custom-error-icon2').length).toBe(2);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/41621
|
||||
it('should not override value when pass `undefined` to require', async () => {
|
||||
// When require is `undefined`, the `isRequire` calculation logic should be preserved
|
||||
|
@ -7,7 +7,7 @@ import * as React from 'react';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import type { ColProps } from '../grid/col';
|
||||
import type { FormInstance, RequiredMark } from './Form';
|
||||
import type { ValidateStatus } from './FormItem';
|
||||
import type { ValidateStatus, FeedbackIcons } from './FormItem';
|
||||
import type { FormLabelAlign } from './interface';
|
||||
|
||||
/** Form Context. Set top form style and pass to Form Item usage. */
|
||||
@ -22,6 +22,7 @@ export interface FormContextProps {
|
||||
requiredMark?: RequiredMark;
|
||||
itemRef: (name: (string | number)[]) => (node: React.ReactElement) => void;
|
||||
form?: FormInstance;
|
||||
feedbackIcons?: FeedbackIcons;
|
||||
}
|
||||
|
||||
export const FormContext = React.createContext<FormContextProps>({
|
||||
|
7
components/form/demo/custom-feedback-icons.md
Normal file
7
components/form/demo/custom-feedback-icons.md
Normal file
@ -0,0 +1,7 @@
|
||||
## zh-CN
|
||||
|
||||
自定义反馈图标可以通过 `hasFeedback={{ icons: ... }}` 或 `<Form FeedbackIcons={icons}>` 传递(`Form.Item` 必须具有 `hasFeedback` 属性)。
|
||||
|
||||
## en-US
|
||||
|
||||
Custom feedback icons can be passed by `hasFeedback={{ icons: ... }}` or `<Form feedbackIcons={icons}>` (`Form.Item` must has `hasFeedback` attribute).
|
77
components/form/demo/custom-feedback-icons.tsx
Normal file
77
components/form/demo/custom-feedback-icons.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
import React from 'react';
|
||||
import { uniqueId } from 'lodash';
|
||||
|
||||
import { createStyles, css } from 'antd-style';
|
||||
import { AlertFilled, CloseSquareFilled } from '@ant-design/icons';
|
||||
import { Button, Form, Input, Tooltip } from 'antd';
|
||||
|
||||
const useStyle = createStyles(() => ({
|
||||
'custom-feedback-icons': css`
|
||||
.ant-form-item-feedback-icon {
|
||||
pointer-events: all;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [form] = Form.useForm();
|
||||
const { styles } = useStyle();
|
||||
|
||||
return (
|
||||
<Form
|
||||
name="custom-feedback-icons"
|
||||
form={form}
|
||||
style={{ maxWidth: 600 }}
|
||||
feedbackIcons={({ errors }) => ({
|
||||
error: (
|
||||
<Tooltip
|
||||
key="tooltipKey"
|
||||
title={errors?.map((error) => <div key={uniqueId()}>{error}</div>)}
|
||||
color="red"
|
||||
>
|
||||
<CloseSquareFilled />
|
||||
</Tooltip>
|
||||
),
|
||||
})}
|
||||
>
|
||||
<Form.Item
|
||||
name="custom-feedback-test-item"
|
||||
label="Test"
|
||||
className={styles['custom-feedback-icons']}
|
||||
rules={[{ required: true, type: 'email' }, { min: 10 }]}
|
||||
help=""
|
||||
hasFeedback
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="custom-feedback-test-item2"
|
||||
label="Test"
|
||||
className={styles['custom-feedback-icons']}
|
||||
rules={[{ required: true, type: 'email' }, { min: 10 }]}
|
||||
help=""
|
||||
hasFeedback={{
|
||||
icons: ({ errors }) => ({
|
||||
error: (
|
||||
<Tooltip
|
||||
key="tooltipKey"
|
||||
title={errors?.map((error) => <div key={uniqueId()}>{error}</div>)}
|
||||
color="pink"
|
||||
>
|
||||
<AlertFilled />
|
||||
</Tooltip>
|
||||
),
|
||||
success: false,
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button htmlType="submit">Submit</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
export default App;
|
@ -52,6 +52,7 @@ High performance Form component with data scope management. Including data colle
|
||||
<code src="./demo/label-debug.tsx" debug>label ellipsis</code>
|
||||
<code src="./demo/col-24-debug.tsx" debug>Test col 24 usage</code>
|
||||
<code src="./demo/ref-item.tsx" debug>Ref item</code>
|
||||
<code src="./demo/custom-feedback-icons.tsx" debug>Custom feedback icons</code>
|
||||
<code src="./demo/component-token.tsx" debug>Component Token</code>
|
||||
|
||||
## API
|
||||
@ -67,6 +68,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
||||
| component | Set the Form rendering element. Do not create a DOM node for `false` | ComponentType \| false | form | |
|
||||
| fields | Control of form fields through state management (such as redux). Not recommended for non-strong demand. View [example](#components-form-demo-global-state) | [FieldData](#fielddata)\[] | - | |
|
||||
| form | Form control instance created by `Form.useForm()`. Automatically created when not provided | [FormInstance](#forminstance) | - | |
|
||||
| feedbackIcons | Can be passed custom icons while `Form.Item` element has `hasFeedback` | [FeedbackIcons](#feedbackicons) | - | |
|
||||
| initialValues | Set value by Form initialization or reset | object | - | |
|
||||
| labelAlign | The text align of label of all items | `left` \| `right` | `right` | |
|
||||
| labelWrap | whether label can be wrap | boolean | false | 4.18.0 |
|
||||
@ -122,7 +124,7 @@ Form field component for data bidirectional binding, validation, layout, and so
|
||||
| extra | The extra prompt message. It is similar to help. Usage example: to display error message and prompt message at the same time | ReactNode | - | |
|
||||
| getValueFromEvent | Specify how to get value from event or other onChange arguments | (..args: any\[]) => any | - | |
|
||||
| getValueProps | Additional props with sub component | (value: any) => any | - | 4.2.0 |
|
||||
| hasFeedback | Used with `validateStatus`, this option specifies the validation status icon. Recommended to be used only with `Input` | boolean | false | |
|
||||
| hasFeedback | Used with `validateStatus`, this option specifies the validation status icon. Recommended to be used only with `Input`. Also, It can get feedback icons via icons prop. | boolean \| {icons:[FeedbackIcons](#feedbackicons)} | false | icons: 5.9.0 |
|
||||
| help | The prompt message. If not provided, the prompt message will be generated by the validation rule. | ReactNode | - | |
|
||||
| hidden | Whether to hide Form.Item (still collect and validate value) | boolean | false | 4.4.0 |
|
||||
| htmlFor | Set sub label `htmlFor` | string | - | |
|
||||
@ -158,6 +160,10 @@ Used when there are dependencies between fields. If a field has the `dependencie
|
||||
|
||||
`dependencies` shouldn't be used together with `shouldUpdate`, since it may result in conflicting update logic.
|
||||
|
||||
### FeedbackIcons
|
||||
|
||||
`({status:ValidateStatus, errors: ReactNode, warnings: ReactNode}) => Record<ValidateStatus,ReactNode>`
|
||||
|
||||
### shouldUpdate
|
||||
|
||||
Form updates only the modified field-related components for performance optimization purposes by incremental update. In most cases, you only need to write code or do validation with the [`dependencies`](#dependencies) property. In some specific cases, such as when a new field option appears with a field value changed, or you just want to keep some area updating by form update, you can modify the update logic of Form.Item via the `shouldUpdate`.
|
||||
|
@ -53,6 +53,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*ylFATY6w-ygAAA
|
||||
<code src="./demo/label-debug.tsx" debug>测试 label 省略</code>
|
||||
<code src="./demo/col-24-debug.tsx" debug>测试特殊 col 24 用法</code>
|
||||
<code src="./demo/ref-item.tsx" debug>引用字段</code>
|
||||
<code src="./demo/custom-feedback-icons.tsx" debug>Custom feedback icons</code>
|
||||
<code src="./demo/component-token.tsx" debug>组件 Token</code>
|
||||
|
||||
## API
|
||||
@ -68,6 +69,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*ylFATY6w-ygAAA
|
||||
| component | 设置 Form 渲染元素,为 `false` 则不创建 DOM 节点 | ComponentType \| false | form | |
|
||||
| fields | 通过状态管理(如 redux)控制表单字段,如非强需求不推荐使用。查看[示例](#components-form-demo-global-state) | [FieldData](#fielddata)\[] | - | |
|
||||
| form | 经 `Form.useForm()` 创建的 form 控制实例,不提供时会自动创建 | [FormInstance](#forminstance) | - | |
|
||||
| feedbackIcons | Can be passed custom icons while `Form.Item` element has `hasFeedback` | ({status:ValidateStatus, errors: ReactNode, warnings: ReactNode}) => Record<ValidateStatus,ReactNode> | - | 5.9.0 |
|
||||
| initialValues | 表单默认值,只有初始化以及重置时生效 | object | - | |
|
||||
| labelAlign | label 标签的文本对齐方式 | `left` \| `right` | `right` | |
|
||||
| labelWrap | label 标签的文本换行方式 | boolean | false | 4.18.0 |
|
||||
@ -123,7 +125,7 @@ const validateMessages = {
|
||||
| extra | 额外的提示信息,和 `help` 类似,当需要错误信息和提示文案同时出现时,可以使用这个。 | ReactNode | - | |
|
||||
| getValueFromEvent | 设置如何将 event 的值转换成字段值 | (..args: any\[]) => any | - | |
|
||||
| getValueProps | 为子元素添加额外的属性 | (value: any) => any | - | 4.2.0 |
|
||||
| hasFeedback | 配合 `validateStatus` 属性使用,展示校验状态图标,建议只配合 Input 组件使用 | boolean | false | |
|
||||
| hasFeedback | 配合 `validateStatus` 属性使用,展示校验状态图标,建议只配合 Input 组件使用 此外,它还可以通过 Icons 属性获取反馈图标。 | boolean \| {icons:({status:ValidateStatus, errors: ReactNode, warnings: ReactNode}) => Record<ValidateStatus,ReactNode>} | false | |
|
||||
| help | 提示信息,如不设置,则会根据校验规则自动生成 | ReactNode | - | |
|
||||
| hidden | 是否隐藏字段(依然会收集和校验字段) | boolean | false | 4.4.0 |
|
||||
| htmlFor | 设置子元素 label `htmlFor` 属性 | string | - | |
|
||||
|
Loading…
Reference in New Issue
Block a user