Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 4 commits into from Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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) {
shaodahong marked this conversation as resolved.
Show resolved Hide resolved
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) {
shaodahong marked this conversation as resolved.
Show resolved Hide resolved
return [this.renderLoading(prefixCls), addonAfter];
}

if (!enterButton) return addonAfter;
shaodahong marked this conversation as resolved.
Show resolved Hide resolved

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