feat: Input fields in error are missing multiple ARIA attributes (#36762)

* feat: add implementation and update snapshots

* test: update snapshot

* test: update snapshots

* test: update snapshots

* test: update snapshots
This commit is contained in:
Uladzimir Atroshchanka 2022-08-24 13:07:50 +04:00 committed by GitHub
parent 58ae7821a7
commit c9fd7fb8f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 347 additions and 8 deletions

View File

@ -600,6 +600,7 @@ HTMLCollection [
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="name"
placeholder="Please enter user name"
@ -655,6 +656,7 @@ HTMLCollection [
http://
</span>
<input
aria-required="true"
class="ant-input"
id="url"
placeholder="Please enter url"
@ -710,6 +712,7 @@ HTMLCollection [
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -724,6 +727,7 @@ HTMLCollection [
aria-controls="owner_list"
aria-haspopup="listbox"
aria-owns="owner_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="owner"
@ -887,6 +891,7 @@ HTMLCollection [
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -901,6 +906,7 @@ HTMLCollection [
aria-controls="type_list"
aria-haspopup="listbox"
aria-owns="type_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="type"
@ -1069,6 +1075,7 @@ HTMLCollection [
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -1083,6 +1090,7 @@ HTMLCollection [
aria-controls="approver_list"
aria-haspopup="listbox"
aria-owns="approver_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="approver"
@ -1246,6 +1254,7 @@ HTMLCollection [
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-picker ant-picker-range"
style="width: 100%;"
>
@ -2470,6 +2479,7 @@ HTMLCollection [
class="ant-form-item-control-input-content"
>
<textarea
aria-required="true"
class="ant-input"
id="description"
placeholder="please enter url description"

View File

@ -29,6 +29,7 @@ function toErrorEntity(
}
export interface ErrorListProps {
fieldId?: string;
help?: React.ReactNode;
helpStatus?: ValidateStatus;
errors?: React.ReactNode[];
@ -43,6 +44,7 @@ export default function ErrorList({
errors = EMPTY_LIST,
warnings = EMPTY_LIST,
className: rootClassName,
fieldId,
onVisibleChanged,
}: ErrorListProps) {
const { prefixCls } = React.useContext(FormItemPrefixContext);
@ -69,6 +71,12 @@ export default function ErrorList({
];
}, [help, helpStatus, debounceErrors, debounceWarnings]);
const helpProps: { id?: string } = {};
if (fieldId) {
helpProps.id = `${fieldId}_help`;
}
return (
<CSSMotion
motionDeadline={collapseMotion.motionDeadline}
@ -81,8 +89,10 @@ export default function ErrorList({
return (
<div
{...helpProps}
className={classNames(baseClassName, holderClassName, rootClassName)}
style={holderStyle}
role="alert"
>
<CSSMotionList
keys={fullKeyList}
@ -102,7 +112,6 @@ export default function ErrorList({
return (
<div
key={key}
role="alert"
className={classNames(itemClassName, {
[`${baseClassName}-${errorStatus}`]: errorStatus,
})}

View File

@ -37,11 +37,16 @@ interface MemoInputProps {
value: any;
update: any;
children: React.ReactNode;
childProps: any[];
}
const MemoInput = React.memo(
({ children }: MemoInputProps) => children as JSX.Element,
(prev, next) => prev.value === next.value && prev.update === next.update,
(prev, next) =>
prev.value === next.value &&
prev.update === next.update &&
prev.childProps.length === next.childProps.length &&
prev.childProps.every((value, index) => value === next.childProps[index]),
);
export interface FormItemProps<Values = any>
@ -305,6 +310,25 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
childProps.id = fieldId;
}
if (props.help || mergedErrors.length > 0 || mergedWarnings.length > 0 || props.extra) {
const describedbyArr = [];
if (props.help || mergedErrors.length > 0) {
describedbyArr.push(`${fieldId}_help`);
}
if (props.extra) {
describedbyArr.push(`${fieldId}_extra`);
}
childProps['aria-describedby'] = describedbyArr.join(' ');
}
if (mergedErrors.length > 0) {
childProps['aria-invalid'] = 'true';
}
if (isRequired) {
childProps['aria-required'] = 'true';
}
if (supportRef(children)) {
childProps.ref = getItemRef(mergedName, children);
}
@ -322,8 +346,19 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
};
});
// List of props that need to be watched for changes -> if changes are detected in MemoInput -> rerender
const watchingChildProps = [
childProps['aria-required'],
childProps['aria-invalid'],
childProps['aria-describedby'],
];
childNode = (
<MemoInput value={mergedControl[props.valuePropName || 'value']} update={children}>
<MemoInput
value={mergedControl[props.valuePropName || 'value']}
update={children}
childProps={watchingChildProps}
>
{cloneElement(children, childProps)}
</MemoInput>
);

View File

@ -32,6 +32,7 @@ export interface FormItemInputProps {
extra?: React.ReactNode;
status?: ValidateStatus;
help?: React.ReactNode;
fieldId?: string;
}
const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = props => {
@ -45,6 +46,7 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
_internalItemRender: formItemRender,
extra,
help,
fieldId,
marginBottom,
onErrorVisibleChanged,
} = props;
@ -72,6 +74,7 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
<div style={{ display: 'flex', flexWrap: 'nowrap' }}>
<FormItemPrefixContext.Provider value={formItemContext}>
<ErrorList
fieldId={fieldId}
errors={errors}
warnings={warnings}
help={help}
@ -84,9 +87,19 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
</div>
) : null;
const extraProps: { id?: string } = {};
if (fieldId) {
extraProps.id = `${fieldId}_extra`;
}
// If extra = 0, && will goes wrong
// 0&&error -> 0
const extraDom = extra ? <div className={`${baseClassName}-extra`}>{extra}</div> : null;
const extraDom = extra ? (
<div {...extraProps} className={`${baseClassName}-extra`}>
{extra}
</div>
) : null;
const dom =
formItemRender && formItemRender.mark === 'pro_table_render' && formItemRender.render ? (

View File

@ -41,6 +41,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-0"
placeholder="placeholder"
@ -84,6 +85,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -98,6 +100,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
aria-controls="advanced_search_field-1_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-1_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-1"
@ -262,6 +265,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-2"
placeholder="placeholder"
@ -305,6 +309,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-3"
placeholder="placeholder"
@ -348,6 +353,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -362,6 +368,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
aria-controls="advanced_search_field-4_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-4_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-4"
@ -526,6 +533,7 @@ exports[`renders ./components/form/demo/advanced-search.md extend context correc
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-5"
placeholder="placeholder"
@ -631,6 +639,7 @@ exports[`renders ./components/form/demo/basic.md extend context correctly 1`] =
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="basic_username"
type="text"
@ -672,6 +681,7 @@ exports[`renders ./components/form/demo/basic.md extend context correctly 1`] =
>
<input
action="click"
aria-required="true"
class="ant-input"
id="basic_password"
type="password"
@ -815,6 +825,7 @@ Array [
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="basic_username"
type="text"
@ -856,6 +867,7 @@ Array [
>
<input
action="click"
aria-required="true"
class="ant-input"
id="basic_password"
type="password"
@ -1184,6 +1196,7 @@ Array [
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="responsive_username"
type="text"
@ -1225,6 +1238,7 @@ Array [
>
<input
action="click"
aria-required="true"
class="ant-input"
id="responsive_password"
type="password"
@ -1601,6 +1615,7 @@ exports[`renders ./components/form/demo/control-hooks.md extend context correctl
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="control-hooks_note"
type="text"
@ -1638,6 +1653,7 @@ exports[`renders ./components/form/demo/control-hooks.md extend context correctl
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
@ -1652,6 +1668,7 @@ exports[`renders ./components/form/demo/control-hooks.md extend context correctl
aria-controls="control-hooks_gender_list"
aria-haspopup="listbox"
aria-owns="control-hooks_gender_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="control-hooks_gender"
@ -1879,6 +1896,7 @@ exports[`renders ./components/form/demo/control-ref.md extend context correctly
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="control-ref_note"
type="text"
@ -1916,6 +1934,7 @@ exports[`renders ./components/form/demo/control-ref.md extend context correctly
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
@ -1930,6 +1949,7 @@ exports[`renders ./components/form/demo/control-ref.md extend context correctly
aria-controls="control-ref_gender_list"
aria-haspopup="listbox"
aria-owns="control-ref_gender_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="control-ref_gender"
@ -5972,6 +5992,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.md extend con
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -5986,6 +6007,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.md extend con
aria-controls="dynamic_form_nest_item_area_list"
aria-haspopup="listbox"
aria-owns="dynamic_form_nest_item_area_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="dynamic_form_nest_item_area"
@ -6347,6 +6369,7 @@ exports[`renders ./components/form/demo/dynamic-rule.md extend context correctly
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="dynamic_rule_username"
placeholder="Please input your name"
@ -6497,6 +6520,7 @@ exports[`renders ./components/form/demo/form-context.md extend context correctly
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="basicForm_group"
type="text"
@ -6648,6 +6672,7 @@ Array [
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="global_state_username"
type="text"
@ -6721,6 +6746,7 @@ exports[`renders ./components/form/demo/inline-login.md extend context correctly
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="horizontal_login_username"
placeholder="Username"
@ -6775,6 +6801,7 @@ exports[`renders ./components/form/demo/inline-login.md extend context correctly
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="horizontal_login_password"
placeholder="Password"
@ -7209,6 +7236,7 @@ exports[`renders ./components/form/demo/layout-can-wrap.md extend context correc
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="wrap_username"
type="text"
@ -7248,6 +7276,7 @@ exports[`renders ./components/form/demo/layout-can-wrap.md extend context correc
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="wrap_password"
type="text"
@ -7333,6 +7362,7 @@ exports[`renders ./components/form/demo/nest-messages.md extend context correctl
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="nest-messages_user_name"
type="text"
@ -7635,6 +7665,7 @@ exports[`renders ./components/form/demo/normal-login.md extend context correctly
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="normal_login_username"
placeholder="Username"
@ -7689,6 +7720,7 @@ exports[`renders ./components/form/demo/normal-login.md extend context correctly
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="normal_login_password"
placeholder="Password"
@ -7902,6 +7934,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="register_email"
type="text"
@ -7943,6 +7976,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
>
<input
action="click"
aria-required="true"
class="ant-input"
id="register_password"
type="password"
@ -8012,6 +8046,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
>
<input
action="click"
aria-required="true"
class="ant-input"
id="register_confirm"
type="password"
@ -8124,6 +8159,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="register_nickname"
type="text"
@ -8161,6 +8197,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-cascader ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
@ -8174,6 +8211,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
aria-controls="register_residence_list"
aria-haspopup="listbox"
aria-owns="register_residence_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="register_residence"
@ -8521,6 +8559,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
</div>
</span>
<input
aria-required="true"
class="ant-input"
id="register_phone"
type="text"
@ -8631,6 +8670,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-input-number-input-wrap"
>
<input
aria-required="true"
autocomplete="off"
class="ant-input-number-input"
id="register_donation"
@ -8818,6 +8858,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
@ -8832,6 +8873,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
aria-controls="register_website_list"
aria-haspopup="listbox"
aria-owns="register_website_list"
aria-required="true"
autocomplete="off"
class="ant-input ant-select-selection-search-input"
id="register_website"
@ -8897,6 +8939,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
data-count="0 / 100"
>
<textarea
aria-required="true"
class="ant-input"
id="register_intro"
/>
@ -8933,6 +8976,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -8947,6 +8991,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
aria-controls="register_gender_list"
aria-haspopup="listbox"
aria-owns="register_gender_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="register_gender"
@ -9129,6 +9174,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
style="padding-left:4px;padding-right:4px"
>
<input
aria-required="true"
class="ant-input"
id="register_captcha"
type="text"
@ -10986,6 +11032,7 @@ exports[`renders ./components/form/demo/time-related-controls.md extend context
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_date-picker"
placeholder="Select date"
@ -11611,6 +11658,7 @@ exports[`renders ./components/form/demo/time-related-controls.md extend context
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_date-time-picker"
placeholder="Select date"
@ -13589,6 +13637,7 @@ exports[`renders ./components/form/demo/time-related-controls.md extend context
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_month-picker"
placeholder="Select month"
@ -13844,6 +13893,7 @@ exports[`renders ./components/form/demo/time-related-controls.md extend context
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-picker ant-picker-range"
>
<div
@ -15054,6 +15104,7 @@ exports[`renders ./components/form/demo/time-related-controls.md extend context
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-picker ant-picker-range"
>
<div
@ -17085,6 +17136,7 @@ exports[`renders ./components/form/demo/time-related-controls.md extend context
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_time-picker"
placeholder="Select time"
@ -18748,6 +18800,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-has-feedback ant-select-single ant-select-show-arrow"
>
<div
@ -18762,6 +18815,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
aria-controls="validate_other_select_list"
aria-haspopup="listbox"
aria-owns="validate_other_select_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="validate_other_select"
@ -18920,6 +18974,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-multiple ant-select-show-search"
>
<div
@ -18942,6 +18997,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
aria-controls="validate_other_select-multiple_list"
aria-haspopup="listbox"
aria-owns="validate_other_select-multiple_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="validate_other_select-multiple"
@ -19475,6 +19531,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-radio-group ant-radio-group-outline"
id="validate_other_radio-button"
>
@ -20094,6 +20151,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
>
<input
accept=""
aria-describedby="validate_other_upload_extra"
id="validate_other_upload"
style="display:none"
type="file"
@ -20135,6 +20193,7 @@ exports[`renders ./components/form/demo/validate-other.md extend context correct
</div>
<div
class="ant-form-item-extra"
id="validate_other_upload_extra"
>
longgggggggggggggggggggggggggggggggggg
</div>
@ -26406,6 +26465,7 @@ exports[`renders ./components/form/demo/warning-only.md extend context correctly
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="url"
placeholder="input placeholder"

View File

@ -41,6 +41,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-0"
placeholder="placeholder"
@ -84,6 +85,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -98,6 +100,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
aria-controls="advanced_search_field-1_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-1_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-1"
@ -180,6 +183,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-2"
placeholder="placeholder"
@ -223,6 +227,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-3"
placeholder="placeholder"
@ -266,6 +271,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -280,6 +286,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
aria-controls="advanced_search_field-4_list"
aria-haspopup="listbox"
aria-owns="advanced_search_field-4_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="advanced_search_field-4"
@ -362,6 +369,7 @@ exports[`renders ./components/form/demo/advanced-search.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="advanced_search_field-5"
placeholder="placeholder"
@ -467,6 +475,7 @@ exports[`renders ./components/form/demo/basic.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="basic_username"
type="text"
@ -508,6 +517,7 @@ exports[`renders ./components/form/demo/basic.md correctly 1`] = `
>
<input
action="click"
aria-required="true"
class="ant-input"
id="basic_password"
type="password"
@ -651,6 +661,7 @@ Array [
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="basic_username"
type="text"
@ -692,6 +703,7 @@ Array [
>
<input
action="click"
aria-required="true"
class="ant-input"
id="basic_password"
type="password"
@ -913,6 +925,7 @@ Array [
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="responsive_username"
type="text"
@ -954,6 +967,7 @@ Array [
>
<input
action="click"
aria-required="true"
class="ant-input"
id="responsive_password"
type="password"
@ -1223,6 +1237,7 @@ exports[`renders ./components/form/demo/control-hooks.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="control-hooks_note"
type="text"
@ -1260,6 +1275,7 @@ exports[`renders ./components/form/demo/control-hooks.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
@ -1274,6 +1290,7 @@ exports[`renders ./components/form/demo/control-hooks.md correctly 1`] = `
aria-controls="control-hooks_gender_list"
aria-haspopup="listbox"
aria-owns="control-hooks_gender_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="control-hooks_gender"
@ -1402,6 +1419,7 @@ exports[`renders ./components/form/demo/control-ref.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="control-ref_note"
type="text"
@ -1439,6 +1457,7 @@ exports[`renders ./components/form/demo/control-ref.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
@ -1453,6 +1472,7 @@ exports[`renders ./components/form/demo/control-ref.md correctly 1`] = `
aria-controls="control-ref_gender_list"
aria-haspopup="listbox"
aria-owns="control-ref_gender_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="control-ref_gender"
@ -3455,6 +3475,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.md correctly
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -3469,6 +3490,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.md correctly
aria-controls="dynamic_form_nest_item_area_list"
aria-haspopup="listbox"
aria-owns="dynamic_form_nest_item_area_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="dynamic_form_nest_item_area"
@ -3748,6 +3770,7 @@ exports[`renders ./components/form/demo/dynamic-rule.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="dynamic_rule_username"
placeholder="Please input your name"
@ -3898,6 +3921,7 @@ exports[`renders ./components/form/demo/form-context.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="basicForm_group"
type="text"
@ -4049,6 +4073,7 @@ Array [
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="global_state_username"
type="text"
@ -4122,6 +4147,7 @@ exports[`renders ./components/form/demo/inline-login.md correctly 1`] = `
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="horizontal_login_username"
placeholder="Username"
@ -4176,6 +4202,7 @@ exports[`renders ./components/form/demo/inline-login.md correctly 1`] = `
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="horizontal_login_password"
placeholder="Password"
@ -4610,6 +4637,7 @@ exports[`renders ./components/form/demo/layout-can-wrap.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="wrap_username"
type="text"
@ -4649,6 +4677,7 @@ exports[`renders ./components/form/demo/layout-can-wrap.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="wrap_password"
type="text"
@ -4734,6 +4763,7 @@ exports[`renders ./components/form/demo/nest-messages.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="nest-messages_user_name"
type="text"
@ -5036,6 +5066,7 @@ exports[`renders ./components/form/demo/normal-login.md correctly 1`] = `
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="normal_login_username"
placeholder="Username"
@ -5090,6 +5121,7 @@ exports[`renders ./components/form/demo/normal-login.md correctly 1`] = `
</span>
</span>
<input
aria-required="true"
class="ant-input"
id="normal_login_password"
placeholder="Password"
@ -5303,6 +5335,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="register_email"
type="text"
@ -5344,6 +5377,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
>
<input
action="click"
aria-required="true"
class="ant-input"
id="register_password"
type="password"
@ -5413,6 +5447,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
>
<input
action="click"
aria-required="true"
class="ant-input"
id="register_confirm"
type="password"
@ -5501,6 +5536,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="register_nickname"
type="text"
@ -5538,6 +5574,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-cascader ant-select-in-form-item ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
@ -5551,6 +5588,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
aria-controls="register_residence_list"
aria-haspopup="listbox"
aria-owns="register_residence_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="register_residence"
@ -5726,6 +5764,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
</div>
</span>
<input
aria-required="true"
class="ant-input"
id="register_phone"
type="text"
@ -5836,6 +5875,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-input-number-input-wrap"
>
<input
aria-required="true"
autocomplete="off"
class="ant-input-number-input"
id="register_donation"
@ -5941,6 +5981,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-auto-complete ant-select-single ant-select-customize-input ant-select-show-search"
>
<div
@ -5955,6 +5996,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
aria-controls="register_website_list"
aria-haspopup="listbox"
aria-owns="register_website_list"
aria-required="true"
autocomplete="off"
class="ant-input ant-select-selection-search-input"
id="register_website"
@ -6006,6 +6048,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
data-count="0 / 100"
>
<textarea
aria-required="true"
class="ant-input"
id="register_intro"
/>
@ -6042,6 +6085,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-single ant-select-show-arrow"
>
<div
@ -6056,6 +6100,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
aria-controls="register_gender_list"
aria-haspopup="listbox"
aria-owns="register_gender_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="register_gender"
@ -6139,6 +6184,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
style="padding-left:4px;padding-right:4px"
>
<input
aria-required="true"
class="ant-input"
id="register_captcha"
type="text"
@ -7186,6 +7232,7 @@ exports[`renders ./components/form/demo/time-related-controls.md correctly 1`] =
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_date-picker"
placeholder="Select date"
@ -7257,6 +7304,7 @@ exports[`renders ./components/form/demo/time-related-controls.md correctly 1`] =
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_date-time-picker"
placeholder="Select date"
@ -7328,6 +7376,7 @@ exports[`renders ./components/form/demo/time-related-controls.md correctly 1`] =
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_month-picker"
placeholder="Select month"
@ -7393,6 +7442,7 @@ exports[`renders ./components/form/demo/time-related-controls.md correctly 1`] =
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-picker ant-picker-range"
>
<div
@ -7506,6 +7556,7 @@ exports[`renders ./components/form/demo/time-related-controls.md correctly 1`] =
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-picker ant-picker-range"
>
<div
@ -7625,6 +7676,7 @@ exports[`renders ./components/form/demo/time-related-controls.md correctly 1`] =
class="ant-picker-input"
>
<input
aria-required="true"
autocomplete="off"
id="time_related_controls_time-picker"
placeholder="Select time"
@ -7923,6 +7975,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-has-feedback ant-select-single ant-select-show-arrow"
>
<div
@ -7937,6 +7990,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
aria-controls="validate_other_select_list"
aria-haspopup="listbox"
aria-owns="validate_other_select_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="validate_other_select"
@ -8013,6 +8067,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-select ant-select-in-form-item ant-select-multiple ant-select-show-search"
>
<div
@ -8035,6 +8090,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
aria-controls="validate_other_select-multiple_list"
aria-haspopup="listbox"
aria-owns="validate_other_select-multiple_list"
aria-required="true"
autocomplete="off"
class="ant-select-selection-search-input"
id="validate_other_select-multiple"
@ -8463,6 +8519,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
aria-required="true"
class="ant-radio-group ant-radio-group-outline"
id="validate_other_radio-button"
>
@ -9082,6 +9139,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
>
<input
accept=""
aria-describedby="validate_other_upload_extra"
id="validate_other_upload"
style="display:none"
type="file"
@ -9123,6 +9181,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
</div>
<div
class="ant-form-item-extra"
id="validate_other_upload_extra"
>
longgggggggggggggggggggggggggggggggggg
</div>
@ -11063,6 +11122,7 @@ exports[`renders ./components/form/demo/warning-only.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<input
aria-required="true"
class="ant-input"
id="url"
placeholder="input placeholder"

View File

@ -203,6 +203,158 @@ describe('Form', () => {
);
});
it('input element should have the prop aria-describedby pointing to the help id when there is a help message', () => {
const wrapper = mount(
<Form>
<Form.Item name="test" help="This is a help">
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-describedby')).toBe('test_help');
const help = wrapper.find('.ant-form-item-explain');
expect(help.prop('id')).toBe('test_help');
});
it('input element should not have the prop aria-describedby pointing to the help id when there is a help message and name is not defined', () => {
const wrapper = mount(
<Form>
<Form.Item help="This is a help">
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-describedby')).toBeUndefined();
const help = wrapper.find('.ant-form-item-explain');
expect(help.prop('id')).toBeUndefined();
});
it('input element should have the prop aria-describedby concatenated with the form name pointing to the help id when there is a help message', () => {
const wrapper = mount(
<Form name="form">
<Form.Item name="test" help="This is a help">
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-describedby')).toBe('form_test_help');
const help = wrapper.find('.ant-form-item-explain');
expect(help.prop('id')).toBe('form_test_help');
});
it('input element should have the prop aria-describedby pointing to the help id when there are errors', async () => {
const wrapper = mount(
<Form>
<Form.Item name="test" rules={[{ len: 3 }, { type: 'number' }]}>
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
input.simulate('change', { target: { value: 'Invalid number' } });
await sleep(800);
wrapper.update();
const inputChanged = wrapper.find('input');
expect(inputChanged.prop('aria-describedby')).toBe('test_help');
const help = wrapper.find('.ant-form-item-explain');
expect(help.prop('id')).toBe('test_help');
});
it('input element should have the prop aria-invalid when there are errors', async () => {
const wrapper = mount(
<Form>
<Form.Item name="test" rules={[{ len: 3 }, { type: 'number' }]}>
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
input.simulate('change', { target: { value: 'Invalid number' } });
await sleep(800);
wrapper.update();
const inputChanged = wrapper.find('input');
expect(inputChanged.prop('aria-invalid')).toBe('true');
});
it('input element should have the prop aria-required when the prop `required` is true', async () => {
const wrapper = mount(
<Form>
<Form.Item name="test" required>
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-required')).toBe('true');
});
it('input element should have the prop aria-required when there is a rule with required', async () => {
const wrapper = mount(
<Form>
<Form.Item name="test" rules={[{ required: true }]}>
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-required')).toBe('true');
});
it('input element should have the prop aria-describedby pointing to the extra id when there is a extra message', () => {
const wrapper = mount(
<Form>
<Form.Item name="test" extra="This is a extra message">
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-describedby')).toBe('test_extra');
const extra = wrapper.find('.ant-form-item-extra');
expect(extra.prop('id')).toBe('test_extra');
});
it('input element should not have the prop aria-describedby pointing to the extra id when there is a extra message and name is not defined', () => {
const wrapper = mount(
<Form>
<Form.Item extra="This is a extra message">
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-describedby')).toBeUndefined();
const extra = wrapper.find('.ant-form-item-extra');
expect(extra.prop('id')).toBeUndefined();
});
it('input element should have the prop aria-describedby pointing to the help and extra id when there is a help and extra message', () => {
const wrapper = mount(
<Form>
<Form.Item name="test" help="This is a help" extra="This is a extra message">
<input />
</Form.Item>
</Form>,
);
const input = wrapper.find('input');
expect(input.prop('aria-describedby')).toBe('test_help test_extra');
});
describe('scrollToField', () => {
function test(name, genForm) {
it(name, () => {
@ -710,9 +862,7 @@ describe('Form', () => {
await sleep(100);
wrapper.update();
await sleep(100);
expect(wrapper.find('.ant-form-item-explain div').getDOMNode().getAttribute('role')).toBe(
'alert',
);
expect(wrapper.find('.ant-form-item-explain').getDOMNode().getAttribute('role')).toBe('alert');
});
it('return same form instance', () => {

View File

@ -112,6 +112,7 @@ exports[`renders ./components/mentions/demo/form.md extend context correctly 1`]
class="ant-mentions"
>
<textarea
aria-required="true"
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"

View File

@ -112,6 +112,7 @@ exports[`renders ./components/mentions/demo/form.md correctly 1`] = `
class="ant-mentions"
>
<textarea
aria-required="true"
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"

View File

@ -120,7 +120,7 @@ return <Menu items={items} />;
#### SubMenuType
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- | --- |
| --- | --- | --- | --- | --- |
| children | 子菜单的菜单项 | [ItemType\[\]](#ItemType) | - | |
| disabled | 是否禁用 | boolean | false | |
| icon | 菜单图标 | ReactNode | - | |