feat: cascader support status (#34086)

* feat: cascader support status

* chore: code clean

* chore: raise bundle size limitation

* chore: code clean
This commit is contained in:
MadCcc 2022-02-17 15:08:13 +08:00 committed by GitHub
parent 483ebb9da1
commit 533bc8740a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 499 additions and 15 deletions

View File

@ -2502,6 +2502,276 @@ Array [
]
`;
exports[`renders ./components/cascader/demo/status.md extend context correctly 1`] = `
<div
class="ant-space ant-space-vertical"
>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<div
class="ant-select ant-cascader ant-select-status-error ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Error
</span>
</div>
<div>
<div
class="ant-select-dropdown ant-cascader-dropdown ant-select-dropdown-empty"
style="opacity:0;pointer-events:none"
>
<div>
<div
class="ant-cascader-menus ant-cascader-menu-empty"
>
<ul
class="ant-cascader-menu"
role="menu"
>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-disabled"
data-path-key="__EMPTY__"
role="menuitemcheckbox"
>
<div
class="ant-cascader-menu-item-content"
>
<div
class="ant-empty ant-empty-normal ant-empty-small"
>
<div
class="ant-empty-image"
>
<svg
class="ant-empty-img-simple"
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
class="ant-empty-img-simple-ellipse"
cx="32"
cy="33"
rx="32"
ry="7"
/>
<g
class="ant-empty-img-simple-g"
fill-rule="nonzero"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
class="ant-empty-img-simple-path"
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
/>
</g>
</g>
</svg>
</div>
<div
class="ant-empty-description"
>
No Data
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-select ant-cascader ant-select-status-warning ant-select-multiple ant-select-allow-clear"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity:1"
>
<div
class="ant-select-selection-search"
style="width:0"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
<span
class="ant-select-selection-placeholder"
>
Warning multiple
</span>
</div>
<div>
<div
class="ant-select-dropdown ant-cascader-dropdown ant-select-dropdown-empty"
style="opacity:0;pointer-events:none"
>
<div>
<div
class="ant-cascader-menus ant-cascader-menu-empty"
>
<ul
class="ant-cascader-menu"
role="menu"
>
<li
aria-checked="false"
class="ant-cascader-menu-item ant-cascader-menu-item-disabled"
data-path-key="__EMPTY__"
role="menuitemcheckbox"
>
<div
class="ant-cascader-menu-item-content"
>
<div
class="ant-empty ant-empty-normal ant-empty-small"
>
<div
class="ant-empty-image"
>
<svg
class="ant-empty-img-simple"
height="41"
viewBox="0 0 64 41"
width="64"
xmlns="http://www.w3.org/2000/svg"
>
<g
fill="none"
fill-rule="evenodd"
transform="translate(0 1)"
>
<ellipse
class="ant-empty-img-simple-ellipse"
cx="32"
cy="33"
rx="32"
ry="7"
/>
<g
class="ant-empty-img-simple-g"
fill-rule="nonzero"
>
<path
d="M55 12.76L44.854 1.258C44.367.474 43.656 0 42.907 0H21.093c-.749 0-1.46.474-1.947 1.257L9 12.761V22h46v-9.24z"
/>
<path
class="ant-empty-img-simple-path"
d="M41.613 15.931c0-1.605.994-2.93 2.227-2.931H55v18.137C55 33.26 53.68 35 52.05 35h-40.1C10.32 35 9 33.259 9 31.137V13h11.16c1.233 0 2.227 1.323 2.227 2.928v.022c0 1.605 1.005 2.901 2.237 2.901h14.752c1.232 0 2.237-1.308 2.237-2.913v-.007z"
/>
</g>
</g>
</svg>
</div>
<div
class="ant-empty-description"
>
No Data
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/cascader/demo/suffix.md extend context correctly 1`] = `
Array [
<div

View File

@ -1036,6 +1036,126 @@ Array [
]
`;
exports[`renders ./components/cascader/demo/status.md correctly 1`] = `
<div
class="ant-space ant-space-vertical"
>
<div
class="ant-space-item"
style="margin-bottom:8px"
>
<div
class="ant-select ant-cascader ant-select-status-error ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
>
<span
class="ant-select-selection-search"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
</span>
<span
class="ant-select-selection-placeholder"
>
Error
</span>
</div>
<span
aria-hidden="true"
class="ant-select-arrow"
style="user-select:none;-webkit-user-select:none"
unselectable="on"
>
<span
aria-label="down"
class="anticon anticon-down ant-select-suffix"
role="img"
>
<svg
aria-hidden="true"
data-icon="down"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
/>
</svg>
</span>
</span>
</div>
</div>
<div
class="ant-space-item"
>
<div
class="ant-select ant-cascader ant-select-status-warning ant-select-multiple ant-select-allow-clear"
>
<div
class="ant-select-selector"
>
<div
class="ant-select-selection-overflow"
>
<div
class="ant-select-selection-overflow-item ant-select-selection-overflow-item-suffix"
style="opacity:1"
>
<div
class="ant-select-selection-search"
style="width:0"
>
<input
aria-autocomplete="list"
aria-controls="undefined_list"
aria-haspopup="listbox"
aria-owns="undefined_list"
autocomplete="off"
class="ant-select-selection-search-input"
readonly=""
role="combobox"
style="opacity:0"
type="search"
unselectable="on"
value=""
/>
<span
aria-hidden="true"
class="ant-select-selection-search-mirror"
>
 
</span>
</div>
</div>
</div>
<span
class="ant-select-selection-placeholder"
>
Warning multiple
</span>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/cascader/demo/suffix.md correctly 1`] = `
Array [
<div

View File

@ -0,0 +1,28 @@
---
order: 16
version: 4.19.0
title:
zh-CN: 自定义状态
en-US: Status
---
## zh-CN
使用 `status` 为 Cascader 添加状态,可选 `error` 或者 `warning`
## en-US
Add status to Cascader with `status`, which could be `error` or `warning`.
```tsx
import { Cascader, Space } from 'antd';
const Validation: React.FC = () => (
<Space direction="vertical">
<Cascader status="error" placeholder="Error" />
<Cascader status="warning" multiple placeholder="Warning multiple" />
</Space>
);
ReactDOM.render(<Validation />, mountNode);
```

View File

@ -45,6 +45,7 @@ Cascade selection box.
| placement | Use preset popup align config from builtinPlacements | `bottomLeft` `bottomRight` `topLeft` `topRight` | `bottomLeft` | 4.17.0 |
| showSearch | Whether show search input in single mode | boolean \| [Object](#showSearch) | false | |
| size | The input size | `large` \| `middle` \| `small` | - | |
| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
| style | The additional style | CSSProperties | - | |
| suffixIcon | The custom suffix icon | ReactNode | - | |
| tagRender | Customize tag render when `multiple` | (props) => ReactNode | - | 4.17.0 |

View File

@ -13,12 +13,15 @@ import omit from 'rc-util/lib/omit';
import RightOutlined from '@ant-design/icons/RightOutlined';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import LeftOutlined from '@ant-design/icons/LeftOutlined';
import { useContext } from 'react';
import devWarning from '../_util/devWarning';
import { ConfigContext } from '../config-provider';
import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import getIcons from '../select/utils/iconUtil';
import { getTransitionName, getTransitionDirection, SelectCommonPlacement } from '../_util/motion';
import { FormItemStatusContext } from '../form/context';
import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
// Align the design since we use `rc-select` in root. This help:
// - List search content will show all content
@ -97,7 +100,8 @@ export type CascaderProps<DataNodeType> = UnionCascaderProps & {
placement?: SelectCommonPlacement;
suffixIcon?: React.ReactNode;
options?: DataNodeType[];
}
status?: InputStatus;
};
export interface CascaderRef {
focus: () => void;
@ -122,6 +126,8 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
notFoundContent,
direction,
getPopupContainer,
status: customStatus,
showArrow,
...rest
} = props;
@ -134,11 +140,15 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
direction: rootDirection,
// virtual,
// dropdownMatchSelectWidth,
} = React.useContext(ConfigContext);
} = useContext(ConfigContext);
const mergedDirection = direction || rootDirection;
const isRtl = mergedDirection === 'rtl';
// =================== Status =====================
const { status: contextStatus, hasFeedback } = useContext(FormItemStatusContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
// =================== Warning =====================
if (process.env.NODE_ENV !== 'production') {
devWarning(
@ -214,8 +224,12 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
);
// ===================== Icons =====================
const mergedShowArrow = showArrow !== undefined ? showArrow : props.loading || !multiple;
const { suffixIcon, removeIcon, clearIcon } = getIcons({
...props,
status: mergedStatus,
hasFeedback,
showArrow: mergedShowArrow,
multiple,
prefixCls,
});
@ -242,6 +256,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
[`${prefixCls}-rtl`]: isRtl,
[`${prefixCls}-borderless`]: !bordered,
},
getStatusClassNames(prefixCls, mergedStatus, hasFeedback),
className,
)}
{...(restProps as any)}
@ -266,6 +281,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
)}
getPopupContainer={getPopupContainer || getContextPopupContainer}
ref={ref}
showArrow={hasFeedback || showArrow}
/>
);
}) as (<OptionType extends BaseOptionType | DefaultOptionType = DefaultOptionType>(

View File

@ -46,6 +46,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/UdS8y8xyZ/Cascader.svg
| placement | 浮层预设位置 | `bottomLeft` `bottomRight` `topLeft` `topRight` | `bottomLeft` | 4.17.0 |
| showSearch | 在选择框中显示搜索框 | boolean \| [Object](#showSearch) | false | |
| size | 输入框大小 | `large` \| `middle` \| `small` | - | |
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
| style | 自定义样式 | CSSProperties | - | |
| suffixIcon | 自定义的选择框后缀图标 | ReactNode | - | |
| tagRender | 自定义 tag 内容,多选时生效 | (props) => ReactNode | - | 4.17.0 |

View File

@ -4,3 +4,5 @@ import './index.less';
// style dependencies
import '../../empty/style';
import '../../select/style';
// deps-lint-skip: form

View File

@ -18667,7 +18667,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
</div>
</div>
<div
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-feedback ant-form-item-is-validating"
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-feedback ant-form-item-has-error"
>
<div
class="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-6"
@ -18689,7 +18689,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -18774,6 +18774,29 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
/>
</svg>
</span>
<span
class="ant-select-feedback-icon"
>
<span
aria-label="close-circle"
class="anticon anticon-close-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</span>
</span>
</span>
</div>
</div>
@ -18782,10 +18805,10 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-explain ant-form-item-explain-connected"
>
<div
class="ant-form-item-explain-validating"
class="ant-form-item-explain-error"
role="alert"
>
The information is being validated...
Something breaks the rule.
</div>
</div>
</div>

View File

@ -7874,7 +7874,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</div>
</div>
<div
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-feedback ant-form-item-is-validating"
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-feedback ant-form-item-has-error"
>
<div
class="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-6"
@ -7896,7 +7896,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-select ant-cascader ant-select-single ant-select-allow-clear ant-select-show-arrow"
class="ant-select ant-cascader ant-select-status-error ant-select-has-feedback ant-select-single ant-select-allow-clear ant-select-show-arrow"
>
<div
class="ant-select-selector"
@ -7950,6 +7950,29 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
/>
</svg>
</span>
<span
class="ant-select-feedback-icon"
>
<span
aria-label="close-circle"
class="anticon anticon-close-circle"
role="img"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
/>
</svg>
</span>
</span>
</span>
</div>
</div>
@ -7958,10 +7981,10 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-explain ant-form-item-explain-connected"
>
<div
class="ant-form-item-explain-validating"
class="ant-form-item-explain-error"
role="alert"
>
The information is being validated...
Something breaks the rule.
</div>
</div>
</div>

View File

@ -107,8 +107,8 @@ ReactDOM.render(
<Form.Item
label="Validating"
hasFeedback
validateStatus="validating"
help="The information is being validated..."
validateStatus="error"
help="Something breaks the rule."
>
<Cascader placeholder="I'm Cascader" options={[{ value: 'xx', label: 'xx' }]} allowClear />
</Form.Item>

View File

@ -300,7 +300,7 @@
},
{
"path": "./dist/antd.min.css",
"maxSize": "65 kB"
"maxSize": "66 kB"
},
{
"path": "./dist/antd.dark.min.css",
@ -308,11 +308,11 @@
},
{
"path": "./dist/antd.compact.min.css",
"maxSize": "65 kB"
"maxSize": "66 kB"
},
{
"path": "./dist/antd.variable.min.css",
"maxSize": "66 kB"
"maxSize": "67 kB"
}
],
"tnpm": {