Skip to content

Commit

Permalink
feat(Input.Search): add loading prop (#18771)
Browse files Browse the repository at this point in the history
* feat(Input.Search): add loading prop

* fix: review change

* optimize input search loading prop doc

* fix: ci fail and onSearch disabled when loading
  • Loading branch information
shaodahong authored and afc163 committed Sep 12, 2019
1 parent f659d23 commit 5cd01d0
Show file tree
Hide file tree
Showing 10 changed files with 770 additions and 452 deletions.
37 changes: 32 additions & 5 deletions components/input/Search.tsx
Expand Up @@ -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> {
Expand All @@ -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);
}
Expand All @@ -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 = (
Expand All @@ -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') {
Expand Down
7 changes: 7 additions & 0 deletions components/input/__tests__/Search.test.js
Expand Up @@ -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();
});
});
79 changes: 79 additions & 0 deletions components/input/__tests__/__snapshots__/Search.test.js.snap
Expand Up @@ -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>
`;
163 changes: 163 additions & 0 deletions components/input/__tests__/__snapshots__/demo.test.js.snap
Expand Up @@ -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"
Expand Down
41 changes: 41 additions & 0 deletions components/input/demo/search-input-loading.md
@@ -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,
);
```
1 change: 1 addition & 0 deletions components/input/index.en-US.md
Expand Up @@ -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`.

Expand Down
1 change: 1 addition & 0 deletions components/input/index.zh-CN.md
Expand Up @@ -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 一致。

Expand Down
1 change: 0 additions & 1 deletion components/input/style/search-input.less
Expand Up @@ -26,7 +26,6 @@
border: 0;

.@{search-prefix}-button {
width: 100%;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
Expand Down

0 comments on commit 5cd01d0

Please sign in to comment.