feat(Input.Search): add loading prop (#18771)

* feat(Input.Search): add loading prop

* fix: review change

* optimize input search loading prop doc

* fix: ci fail and onSearch disabled when loading
This commit is contained in:
骗你是小猫咪 2019-09-12 22:32:29 +08:00 committed by 偏右
parent f659d23d22
commit 5cd01d0470
10 changed files with 1010 additions and 692 deletions

View File

@ -11,7 +11,8 @@ export interface SearchProps extends InputProps {
value: string,
event?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>,
) => void;
enterButton?: boolean | React.ReactNode;
enterButton?: React.ReactNode;
loading?: boolean;
}
export default class Search extends React.Component<SearchProps, any> {
@ -26,7 +27,10 @@ export default class Search extends React.Component<SearchProps, any> {
};
onSearch = (e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>) => {
const { onSearch } = this.props;
const { onSearch, loading } = this.props;
if (loading) return;
if (onSearch) {
onSearch(this.input.input.value, e);
}
@ -41,8 +45,26 @@ export default class Search extends React.Component<SearchProps, any> {
this.input.blur();
}
renderLoading = (prefixCls: string) => {
const { enterButton, size } = this.props;
if (enterButton) {
return (
<Button className={`${prefixCls}-button`} type="primary" size={size} key="enterButton">
<Icon type="loading" />
</Button>
);
}
return <Icon className={`${prefixCls}-icon`} type="loading" />;
};
renderSuffix = (prefixCls: string) => {
const { suffix, enterButton } = this.props;
const { suffix, enterButton, loading } = this.props;
if (loading && !enterButton) {
return [suffix, this.renderLoading(prefixCls)];
}
if (enterButton) return suffix;
const node = (
@ -68,10 +90,15 @@ export default class Search extends React.Component<SearchProps, any> {
};
renderAddonAfter = (prefixCls: string) => {
const { enterButton, size, disabled, addonAfter } = this.props;
if (!enterButton) return addonAfter;
const { enterButton, size, disabled, addonAfter, loading } = this.props;
const btnClassName = `${prefixCls}-button`;
if (loading && enterButton) {
return [this.renderLoading(prefixCls), addonAfter];
}
if (!enterButton) return addonAfter;
let button: React.ReactNode;
const enterButtonAsElement = enterButton as React.ReactElement<any>;
if (enterButtonAsElement.type === Button || enterButtonAsElement.type === 'button') {

View File

@ -137,4 +137,11 @@ describe('Input.Search', () => {
expect(wrapper.render()).toMatchSnapshot();
expect(wrapperWithEnterButton.render()).toMatchSnapshot();
});
it('should support loading', () => {
const wrapper = mount(<Search loading />);
const wrapperWithEnterButton = mount(<Search loading enterButton />);
expect(wrapper.render()).toMatchSnapshot();
expect(wrapperWithEnterButton.render()).toMatchSnapshot();
});
});

View File

@ -150,3 +150,82 @@ exports[`Input.Search should support custom button 1`] = `
</span>
</span>
`;
exports[`Input.Search should support loading 1`] = `
<span
class="ant-input-search ant-input-affix-wrapper"
>
<input
class="ant-input"
type="text"
value=""
/>
<span
class="ant-input-suffix"
>
<i
aria-label="icon: loading"
class="anticon anticon-loading ant-input-search-icon"
>
<svg
aria-hidden="true"
class="anticon-spin"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</i>
</span>
</span>
`;
exports[`Input.Search should support loading 2`] = `
<span
class="ant-input-search ant-input-search-enter-button ant-input-group-wrapper"
>
<span
class="ant-input-wrapper ant-input-group"
>
<input
class="ant-input"
type="text"
value=""
/>
<span
class="ant-input-group-addon"
>
<button
class="ant-btn ant-input-search-button ant-btn-primary"
type="button"
>
<i
aria-label="icon: loading"
class="anticon anticon-loading"
>
<svg
aria-hidden="true"
class="anticon-spin"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</i>
</button>
</span>
</span>
</span>
`;

View File

@ -1811,6 +1811,169 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
</div>
`;
exports[`renders ./components/input/demo/search-input-loading.md correctly 1`] = `
<div>
<span
class="ant-input-search ant-input-affix-wrapper"
>
<input
class="ant-input"
placeholder="input search loading deault"
type="text"
value=""
/>
<span
class="ant-input-suffix"
>
<i
aria-label="icon: loading"
class="anticon anticon-loading ant-input-search-icon"
>
<svg
aria-hidden="true"
class="anticon-spin"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</i>
</span>
</span>
<br />
<br />
<span
class="ant-input-search ant-input-affix-wrapper"
>
<input
class="ant-input"
placeholder="input search loading with suffix"
type="text"
value=""
/>
<span
class="ant-input-suffix"
>
suffix
<i
aria-label="icon: loading"
class="anticon anticon-loading ant-input-search-icon"
>
<svg
aria-hidden="true"
class="anticon-spin"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</i>
</span>
</span>
<br />
<br />
<span
class="ant-input-search ant-input-search-enter-button ant-input-group-wrapper"
>
<span
class="ant-input-wrapper ant-input-group"
>
<input
class="ant-input"
placeholder="input search loading with enterButton"
type="text"
value=""
/>
<span
class="ant-input-group-addon"
>
<button
class="ant-btn ant-input-search-button ant-btn-primary"
type="button"
>
<i
aria-label="icon: loading"
class="anticon anticon-loading"
>
<svg
aria-hidden="true"
class="anticon-spin"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</i>
</button>
</span>
</span>
</span>
<br />
<br />
<span
class="ant-input-search ant-input-search-enter-button ant-input-group-wrapper"
>
<span
class="ant-input-wrapper ant-input-group"
>
<input
class="ant-input"
placeholder="input search loading with enterButton and addonAfter"
type="text"
value=""
/>
<span
class="ant-input-group-addon"
>
<button
class="ant-btn ant-input-search-button ant-btn-primary"
type="button"
>
<i
aria-label="icon: loading"
class="anticon anticon-loading"
>
<svg
aria-hidden="true"
class="anticon-spin"
data-icon="loading"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 0 0-94.3-139.9 437.71 437.71 0 0 0-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
/>
</svg>
</i>
</button>
addonAfter
</span>
</span>
</span>
</div>
`;
exports[`renders ./components/input/demo/size.md correctly 1`] = `
<div
class="example-input"

View File

@ -0,0 +1,41 @@
---
order: 5
title:
zh-CN: 搜索框 loading
en-US: Search box with loading
---
## zh-CN
用于 `onSearch` 的时候展示 `loading`
## en-US
Search loading when onSearch.
```jsx
import { Input } from 'antd';
const { Search } = Input;
ReactDOM.render(
<div>
<Search placeholder="input search loading deault" loading />
<br />
<br />
<Search placeholder="input search loading with suffix" loading suffix="suffix" />
<br />
<br />
<Search placeholder="input search loading with enterButton" loading enterButton />
<br />
<br />
<Search
placeholder="input search loading with enterButton and addonAfter"
loading
enterButton
addonAfter="addonAfter"
/>
</div>,
mountNode,
);
```

View File

@ -56,6 +56,7 @@ The rest of the props of `Input.TextArea` are the same as the original [textarea
| --- | --- | --- | --- | --- |
| enterButton | to show an enter button after input. This prop is conflict with addon. | boolean\|ReactNode | false | |
| onSearch | The callback function that is triggered when you click on the search-icon or press Enter key. | function(value, event) | | |
| loading | Search box with loading. | boolean | | |
Supports all props of `Input`.

View File

@ -55,6 +55,7 @@ Input 的其他属性和 React 自带的 [input](https://facebook.github.io/reac
| --- | --- | --- | --- | --- |
| enterButton | 是否有确认按钮,可设为按钮文字。该属性会与 addon 冲突。 | boolean\|ReactNode | false | |
| onSearch | 点击搜索或按下回车键时的回调 | function(value, event) | | |
| loading | 搜索 loading | boolean | | |
其余属性和 Input 一致。

View File

@ -26,7 +26,6 @@
border: 0;
.@{search-prefix}-button {
width: 100%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -491,7 +491,7 @@ exports[`Table renders empty table with fixed columns 1`] = `
>
<tr>
<th
class="ant-table-fixed-columns-in-body"
class="ant-table-fixed-columns-in-body ant-table-row-cell-break-word"
>
<span
class="ant-table-header-column"
@ -509,7 +509,7 @@ exports[`Table renders empty table with fixed columns 1`] = `
</span>
</th>
<th
class="ant-table-fixed-columns-in-body"
class="ant-table-fixed-columns-in-body ant-table-row-cell-break-word"
>
<span
class="ant-table-header-column"
@ -671,7 +671,7 @@ exports[`Table renders empty table with fixed columns 1`] = `
</span>
</th>
<th
class="ant-table-fixed-columns-in-body"
class="ant-table-fixed-columns-in-body ant-table-row-cell-break-word"
>
<span
class="ant-table-header-column"
@ -771,7 +771,7 @@ exports[`Table renders empty table with fixed columns 1`] = `
>
<tr>
<th
class=""
class="ant-table-row-cell-break-word"
>
<span
class="ant-table-header-column"
@ -789,7 +789,7 @@ exports[`Table renders empty table with fixed columns 1`] = `
</span>
</th>
<th
class=""
class="ant-table-row-cell-break-word"
>
<span
class="ant-table-header-column"
@ -838,7 +838,7 @@ exports[`Table renders empty table with fixed columns 1`] = `
>
<tr>
<th
class=""
class="ant-table-row-cell-break-word"
>
<span
class="ant-table-header-column"