feat: Input add NumericInput demo & update searchInput demo (#3861)

* Input
add NumericInput demo
update searchInput

* Input

- add Input.Search
- update NumericInput

* snap update
This commit is contained in:
ddcat1115 2016-11-24 14:03:57 +08:00 committed by Benjy Cui
parent 91b2242f44
commit 73c776e73d
9 changed files with 281 additions and 105 deletions

View File

@ -57,6 +57,7 @@ export interface InputProps {
export default class Input extends Component<InputProps, any> {
static Group: any;
static Search: any;
static defaultProps = {
disabled: false,
prefixCls: 'ant-input',

View File

@ -0,0 +1,83 @@
import React from 'react';
import classNames from 'classnames';
import Input from './Input';
import Icon from '../icon';
import splitObject from '../_util/splitObject';
import omit from 'omit.js';
export interface SearchProps {
className?: string;
placeholder?: string;
prefixCls?: string;
style?: React.CSSProperties;
defaultValue?: any;
value?: any;
onChange?: React.FormEventHandler<any>;
onSearch?: React.FormEventHandler<any>;
}
export default class Search extends React.Component<SearchProps, any> {
static defaultProps = {
prefixCls: 'ant-input-search',
};
constructor(props) {
super(props);
let value;
if ('value' in props) {
value = props.value;
} else if ('defaultValue' in props) {
value = props.defaultValue;
} else {
value = '';
}
this.state = {
value,
focus: false,
};
}
onChange = (e) => {
if (!('value' in this.props)) {
this.setState({ value: e.target.value });
}
const onChange = this.props.onChange;
if (onChange) {
onChange(e);
}
}
onSearch = () => {
if (this.state.focus && this.props.onSearch) {
this.props.onSearch(this.state.value);
} else if (!this.state.focus) {
this.setState({ focus: true });
}
}
render() {
const [{ className, placeholder, prefixCls }, others] = splitObject(
this.props, ['className', 'placeholder', 'prefixCls']
);
// Fix https://fb.me/react-unknown-prop
const otherProps = omit(others, [
'defaultValue',
'value',
'onChange',
'onSearch',
]);
const wrapperCls = classNames({
[`${prefixCls}-wrapper`]: true,
[`${prefixCls}-wrapper-focus`]: this.state.focus,
[className]: !!className,
});
return (
<div className={wrapperCls} {...otherProps}>
<Input
className={prefixCls}
placeholder={placeholder}
value={this.state.value}
onChange={this.onChange}
onPressEnter={this.onSearch}
/>
<Icon className={`${prefixCls}-icon`} onClick={this.onSearch} type="search" />
</div>
);
}
}

View File

@ -14,60 +14,10 @@ title:
Example of creating a search box by grouping a standard input with a search button.
````jsx
import { Input, Button } from 'antd';
import classNames from 'classnames';
const InputGroup = Input.Group;
const SearchInput = React.createClass({
getInitialState() {
return {
value: '',
focus: false,
};
},
handleInputChange(e) {
this.setState({
value: e.target.value,
});
},
handleFocusBlur(e) {
this.setState({
focus: e.target === document.activeElement,
});
},
handleSearch() {
if (this.props.onSearch) {
this.props.onSearch(this.state.value);
}
},
render() {
const { style, size, placeholder } = this.props;
const btnCls = classNames({
'ant-search-btn': true,
'ant-search-btn-noempty': !!this.state.value.trim(),
});
const searchCls = classNames({
'ant-search-input': true,
'ant-search-input-focus': this.state.focus,
});
return (
<div className="ant-search-input-wrapper" style={style}>
<InputGroup className={searchCls}>
<Input placeholder={placeholder} value={this.state.value} onChange={this.handleInputChange}
onFocus={this.handleFocusBlur} onBlur={this.handleFocusBlur} onPressEnter={this.handleSearch}
/>
<div className="ant-input-group-wrap">
<Button icon="search" className={btnCls} size={size} onClick={this.handleSearch} />
</div>
</InputGroup>
</div>
);
},
});
import { Input } from 'antd';
const InputSearch = Input.Search;
ReactDOM.render(
<SearchInput placeholder="input search text"
onSearch={value => console.log(value)} style={{ width: 200 }}
/>
<InputSearch placeholder="input search text" onSearch={value => console.log(value)} />
, mountNode);
````

View File

@ -0,0 +1,118 @@
---
order: 7
title:
zh-CN: 数值输入框
en-US: Numeric Input
---
## zh-CN
结合 [Tooltip](/components/tooltip) 组件,实现一个数值输入框,方便内容超长时的全量展现。
## en-US
You can use the Input in conjunction with [Tooltip](/components/tooltip) component to create a Numeric Input, which can provide a good experience for extra-long content display.
````jsx
import { Input, Tooltip } from 'antd';
function formatNumber(value) {
value += '';
const list = value.split('.');
const prefix = list[0].charAt(0) === '-' ? '-' : '';
let num = prefix ? list[0].slice(1) : list[0];
let result = '';
while (num.length > 3) {
result = `,${num.slice(-3)}${result}`;
num = num.slice(0, num.length - 3);
}
if (num) {
result = num + result;
}
return `${prefix}${result}${list[1] ? `.${list[1]}` : ''}`;
}
class NumericInput extends React.Component {
onChange = (e) => {
const { value } = e.target;
const reg = /^-?(0|[1-9][0-9]*)(\.[0-9]*)?$/;
if ((!isNaN(value) && reg.test(value)) || value === '' || value === '-') {
this.props.onChange(value);
}
}
// '.' at the end or only '-' in the input box.
onBlur = () => {
const { value } = this.props;
if (value.charAt(value.length - 1) === '.' || value === '-') {
this.props.onChange({ value: value.slice(0, -1) });
}
if (this.props.onBlur) {
this.props.onBlur();
}
}
render() {
const { value } = this.props;
const title = (value ?
(<span className="numeric-input-title">
{value !== '-' ? formatNumber(value) : '-'}
</span>) : '');
return (
<div>
<Tooltip
trigger={['focus']}
title={title}
placement="topLeft"
overlayClassName="numeric-input"
>
<Input
{...this.props}
onChange={this.onChange}
onBlur={this.onBlur}
placeholder="input a number"
maxLength="25"
/>
</Tooltip>
</div>
);
}
}
class NumericInputDemo extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
}
onChange = (value) => {
this.setState({ value });
}
render() {
const { value } = this.state;
return (
<div className="numeric-input-demo">
<NumericInput value={value} onChange={this.onChange} />
</div>
);
}
}
ReactDOM.render(<NumericInputDemo />, mountNode);
````
````css
/* to prevent the arrow overflow the popup container,
or the height is not enough when content is empty */
.numeric-input .ant-tooltip-inner {
min-width: 32px;
min-height: 37px;
}
.numeric-input .numeric-input-title {
font-size: 14px;
}
.numeric-input-demo {
width: 120px;
}
````

View File

@ -32,6 +32,15 @@ Keyboard and mouse can be used for providing or changing data.
> When `Input` is used in a `Form.Item` context, if the `Form.Item` has the `id` and `options` props defined
then `value`, `defaultValue`, and `id` props are automatically set.
#### Input.Search
| Property | Description | Type | Available Values | Default |
|-----------|------------------------------------------|------------|-------|--------|
| defaultValue | The initial value. | any | | |
| value | The content value. | any | | |
| onChange | The callback function that is triggered when you change the value. | function(e) | | |
| onSearch | The callback function that is triggered when you click on the search-icon or press Enter key. | function | | |
#### Input.Group
| Property | Description | Type | Available Values | Default |

View File

@ -1,5 +1,7 @@
import Input from './Input';
import Group from './Group';
import Search from './Search';
Input.Group = Group;
Input.Search = Search;
export default Input;

View File

@ -31,6 +31,15 @@ title: Input
> 如果 `Input``Form.Item` 内,并且 `Form.Item` 设置了 `id``options` 属性,则 `value` `defaultValue``id` 属性会被自动设置。
#### Input.Search
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
|-----------|------------------------------------------|------------|-------|--------|
| defaultValue | 初始默认值 | any | | |
| value | value 值 | any | | |
| onChange | 值改变的回调 | function(e) | | |
| onSearch | 点击搜索或按下回车键时的回调 | function | | |
#### Input.Group
| 参数 | 说明 | 类型 | 可选值 | 默认值 |

View File

@ -3,44 +3,42 @@
@import "../../button/style/mixin";
@import "./mixin";
.@{ant-prefix}-search-input-wrapper {
.@{ant-prefix}-input-search-wrapper {
display: inline-block;
vertical-align: middle;
position: relative;
min-width: 24px;
height: @input-height-base;
.@{ant-prefix}-input-search {
opacity: 0;
width: 0;
transition: all .3s ease;
}
.@{ant-prefix}-input-search-icon {
position: absolute;
line-height: @input-height-base;
left: 0;
cursor: pointer;
font-size: 24px;
transition: all .3s ease;
&:hover {
color: @input-hover-border-color;
}
}
}
.@{ant-prefix}-search-input {
&.@{ant-prefix}-input-group .@{ant-prefix}-input:first-child,
&.@{ant-prefix}-input-group .@{ant-prefix}-select:first-child {
border-radius: @border-radius-base;
position: absolute;
top: -1px;
.@{ant-prefix}-input-search-wrapper-focus {
.@{ant-prefix}-input-search {
opacity: 1;
width: 100%;
}
&.@{ant-prefix}-input-group .@{ant-prefix}-input:first-child {
padding-right: 36px;
}
.@{ant-prefix}-search-btn {
.btn-default;
border-radius: 0 @border-radius-base - 1 @border-radius-base - 1 0;
left: -1px;
position: relative;
border-width: 0 0 0 1px;
z-index: 2;
padding-left: 8px;
padding-right: 8px;
&:hover {
border-color: @border-color-base;
}
}
&&-focus .@{ant-prefix}-search-btn-noempty,
&:hover .@{ant-prefix}-search-btn-noempty {
.btn-primary;
}
.@{ant-prefix}-select-combobox {
.@{ant-prefix}-select-selection__rendered {
margin-right: 29px;
}
.@{ant-prefix}-input-search-icon {
left: 100%;
margin-left: -22px;
font-size: 14px;
}
}

View File

@ -169,28 +169,17 @@ exports[`test renders ./components/input/demo/group.md correctly 1`] = `
exports[`test renders ./components/input/demo/search-input.md correctly 1`] = `
<div
class="ant-search-input-wrapper"
style="width:200px;">
class="ant-input-search-wrapper">
<span
class="ant-input-group ant-search-input">
<span
class="ant-input-wrapper">
<input
class="ant-input"
placeholder="input search text"
type="text"
value="" />
</span>
<div
class="ant-input-group-wrap">
<button
class="ant-btn ant-btn-icon-only ant-search-btn"
type="button">
<i
class="anticon anticon-search " />
</button>
</div>
class="ant-input-wrapper">
<input
class="ant-input ant-input-search"
placeholder="input search text"
type="text"
value="" />
</span>
<i
class="anticon anticon-search ant-input-search-icon" />
</div>
`;
@ -230,3 +219,20 @@ exports[`test renders ./components/input/demo/textarea.md correctly 1`] = `
type="textarea" />
</span>
`;
exports[`test renders ./components/input/demo/tooltip.md correctly 1`] = `
<div
class="numeric-input-demo">
<div>
<span
class="ant-input-wrapper">
<input
class="ant-input"
maxlength="25"
placeholder="input a number"
type="text"
value="" />
</span>
</div>
</div>
`;