feat: update input-number

pull/1845/head
tangjinzhou 2020-02-20 17:45:18 +08:00
parent 356e60a12c
commit 6b6bacc7a1
10 changed files with 185 additions and 138 deletions

View File

@ -1,5 +1,5 @@
module.exports = {
dev: {
componentName: 'input', // dev components
componentName: 'input-number', // dev components
},
};

View File

@ -19,6 +19,7 @@ export default {
// Object.assign(newState, this.getDerivedStateFromProps(getOptionProps(this), { ...this.$data, ...newState }, true) || {})
// }
Object.assign(this.$data, newState);
this.$forceUpdate();
this.$nextTick(() => {
callback && callback();
});

View File

@ -4,7 +4,7 @@ exports[`renders ./components/input-number/demo/basic.md correctly 1`] = `
<div>
<div class="ant-input-number">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up " unselectable="unselectable" role="button" aria-label="Increase Value"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="1" aria-valuemax="10" aria-valuenow="3" class="ant-input-number-input-wrap"><input autocomplete="off" max="10" min="1" step="1" id="inputNumber" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="1" aria-valuemax="10" aria-valuenow="3" autocomplete="off" max="10" min="1" step="1" id="inputNumber" class="ant-input-number-input"></div>
</div>
当前值3
</div>
@ -13,7 +13,7 @@ exports[`renders ./components/input-number/demo/basic.md correctly 1`] = `
exports[`renders ./components/input-number/demo/digit.md correctly 1`] = `
<div class="ant-input-number">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up " unselectable="unselectable" role="button" aria-label="Increase Value"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="0" aria-valuemax="10" class="ant-input-number-input-wrap"><input autocomplete="off" max="10" min="0" step="0.1" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="0" aria-valuemax="10" autocomplete="off" max="10" min="0" step="0.1" class="ant-input-number-input"></div>
</div>
`;
@ -21,7 +21,7 @@ exports[`renders ./components/input-number/demo/disabled.md correctly 1`] = `
<div>
<div class="ant-input-number ant-input-number-disabled">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up " unselectable="unselectable" role="button" aria-label="Increase Value" aria-disabled="true"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value" aria-disabled="true"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="1" aria-valuemax="10" aria-valuenow="3" class="ant-input-number-input-wrap"><input autocomplete="off" disabled="disabled" max="10" min="1" step="1" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="1" aria-valuemax="10" aria-valuenow="3" autocomplete="off" disabled="disabled" max="10" min="1" step="1" class="ant-input-number-input"></div>
</div>
<div style="margin-top: 20px;"><button type="button" class="ant-btn ant-btn-primary"><span>Toggle disabled</span></button></div>
</div>
@ -31,11 +31,11 @@ exports[`renders ./components/input-number/demo/formatter.md correctly 1`] = `
<div>
<div class="ant-input-number">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up " unselectable="unselectable" role="button" aria-label="Increase Value"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="-9007199254740991" aria-valuenow="1000" class="ant-input-number-input-wrap"><input autocomplete="off" min="-9007199254740991" step="1" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="-9007199254740991" aria-valuenow="1000" autocomplete="off" min="-9007199254740991" step="1" class="ant-input-number-input"></div>
</div>
<div class="ant-input-number">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up ant-input-number-handler-up-disabled" unselectable="unselectable" role="button" aria-label="Increase Value" aria-disabled="true"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="0" aria-valuemax="100" aria-valuenow="100" class="ant-input-number-input-wrap"><input autocomplete="off" max="100" min="0" step="1" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="0" aria-valuemax="100" aria-valuenow="100" autocomplete="off" max="100" min="0" step="1" class="ant-input-number-input"></div>
</div>
</div>
`;
@ -44,15 +44,15 @@ exports[`renders ./components/input-number/demo/size.md correctly 1`] = `
<div>
<div class="ant-input-number ant-input-number-lg">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up " unselectable="unselectable" role="button" aria-label="Increase Value"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="1" aria-valuemax="100000" aria-valuenow="3" class="ant-input-number-input-wrap"><input autocomplete="off" max="100000" min="1" step="1" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="1" aria-valuemax="100000" aria-valuenow="3" autocomplete="off" max="100000" min="1" step="1" class="ant-input-number-input"></div>
</div>
<div class="ant-input-number">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up " unselectable="unselectable" role="button" aria-label="Increase Value"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="1" aria-valuemax="100000" aria-valuenow="3" class="ant-input-number-input-wrap"><input autocomplete="off" max="100000" min="1" step="1" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="1" aria-valuemax="100000" aria-valuenow="3" autocomplete="off" max="100000" min="1" step="1" class="ant-input-number-input"></div>
</div>
<div class="ant-input-number ant-input-number-sm">
<div class="ant-input-number-handler-wrap"><span class="ant-input-number-handler ant-input-number-handler-up " unselectable="unselectable" role="button" aria-label="Increase Value"><i aria-label="icon: up" class="ant-input-number-handler-up-inner anticon anticon-up"><svg viewBox="64 64 896 896" data-icon="up" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><path d="M890.5 755.3L537.9 269.2c-12.8-17.6-39-17.6-51.7 0L133.5 755.3A8 8 0 0 0 140 768h75c5.1 0 9.9-2.5 12.9-6.6L512 369.8l284.1 391.6c3 4.1 7.8 6.6 12.9 6.6h75c6.5 0 10.3-7.4 6.5-12.7z"></path></svg></i></span><span class="ant-input-number-handler ant-input-number-handler-down " unselectable="unselectable" role="button" aria-label="Decrease Value"><i aria-label="icon: down" class="ant-input-number-handler-down-inner anticon anticon-down"><svg viewBox="64 64 896 896" data-icon="down" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""><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"></path></svg></i></span></div>
<div role="spinbutton" aria-valuemin="1" aria-valuemax="100000" aria-valuenow="3" class="ant-input-number-input-wrap"><input autocomplete="off" max="100000" min="1" step="1" class="ant-input-number-input"></div>
<div class="ant-input-number-input-wrap"><input role="spinbutton" aria-valuemin="1" aria-valuemax="100000" aria-valuenow="3" autocomplete="off" max="100000" min="1" step="1" class="ant-input-number-input"></div>
</div>
</div>
`;

View File

@ -1,4 +1,29 @@
import { mount } from '@vue/test-utils';
import InputNumber from '..';
import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
focusTest(InputNumber);
describe('InputNumber', () => {
focusTest(InputNumber);
mountTest(InputNumber);
// https://github.com/ant-design/ant-design/issues/13896
it('should return null when blur a empty input number', () => {
const onChange = jest.fn();
const wrapper = mount(
{
render() {
return <InputNumber defaultValue="1" onChange={onChange} />;
},
},
{
sync: false,
},
);
wrapper.find('input').element.value = '';
wrapper.find('input').trigger('input');
expect(onChange).toHaveBeenLastCalledWith('');
wrapper.find('input').trigger('blur');
expect(onChange).toHaveBeenLastCalledWith(null);
});
});

View File

@ -11,15 +11,16 @@
| parser | Specifies the value extracted from formatter | function( string): number | - |
| precision | precision of input value | number | - |
| decimalSeparator | decimal separator | string | - |
| size | width of input box | string | - |
| size | height of input box | string | - |
| step | The number to which the current value is increased or decreased. It can be an integer or decimal. | number\|string | 1 |
| value(v-model) | current value | number | |
### events
| Events Name | Description | Arguments |
| --- | --- | --- |
| change | The callback triggered when the value is changed. | function(value: number \| string) | |
| Events Name | Description | Arguments | Version |
| --- | --- | --- | --- |
| change | The callback triggered when the value is changed. | function(value: number \| string) | | |
| pressEnter | The callback function that is triggered when Enter key is pressed. | function(e) | | 1.5.0 |
## Methods

View File

@ -12,7 +12,7 @@ export const InputNumberProps = {
max: PropTypes.number,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
step: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
defaultValue: PropTypes.number,
defaultValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
tabIndex: PropTypes.number,
disabled: PropTypes.bool,
size: PropTypes.oneOf(['large', 'small', 'default']),

View File

@ -19,9 +19,10 @@
### 事件
| 事件名称 | 说明 | 回调参数 |
| -------- | -------- | --------------------------------- |
| change | 变化回调 | Function(value: number \| string) | |
| 事件名称 | 说明 | 回调参数 | 版本 |
| ---------- | -------------- | --------------------------------- | ---- |
| change | 变化回调 | Function(value: number \| string) | |
| pressEnter | 按下回车的回调 | function(e) | |
## 方法

View File

@ -37,6 +37,7 @@ export default {
return (
<div style="margin: 10px;">
<InputNumber
aria-label="Number input example that demonstrates combination key format"
min={-8000}
max={10000000}
value={this.value}

View File

@ -3,6 +3,7 @@ import Touchable from '../../vc-m-feedback';
import { getListeners } from '../../_util/props-util';
const InputHandler = {
name: 'InputHandler',
props: {
prefixCls: PropTypes.string,
disabled: PropTypes.bool,

View File

@ -1,4 +1,4 @@
// based on rc-input-number 4.4.0
// based on rc-input-number 4.5.5
import PropTypes from '../../_util/vue-types';
import BaseMixin from '../../_util/BaseMixin';
import { initDefaultProps, hasProp, getOptionProps, getListeners } from '../../_util/props-util';
@ -35,6 +35,13 @@ const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
const isValidProps = value => value !== undefined && value !== null;
const isEqual = (oldValue, newValue) =>
newValue === oldValue ||
(typeof newValue === 'number' &&
typeof oldValue === 'number' &&
isNaN(newValue) &&
isNaN(oldValue));
const inputNumberProps = {
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
defaultValue: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
@ -73,7 +80,7 @@ const inputNumberProps = {
};
export default {
name: 'InputNumber',
name: 'VCInputNumber',
mixins: [BaseMixin],
model: {
prop: 'value',
@ -90,17 +97,18 @@ export default {
autoComplete: 'off',
}),
data() {
const props = getOptionProps(this);
this.prevProps = { ...props };
let value;
if (hasProp(this, 'value')) {
if ('value' in props) {
value = this.value;
} else {
value = this.defaultValue;
}
value = this.toNumber(value);
const validValue = this.getValidValue(this.toNumber(value));
return {
inputValue: this.toPrecisionAsStep(value),
sValue: value,
inputValue: this.toPrecisionAsStep(validValue),
sValue: validValue,
focused: this.autoFocus,
};
},
@ -112,19 +120,57 @@ export default {
this.updatedFunc();
});
},
beforeUpdate() {
this.$nextTick(() => {
try {
this.start = this.$refs.inputRef.selectionStart;
this.end = this.$refs.inputRef.selectionEnd;
} catch (e) {
// Fix error in Chrome:
// Failed to read the 'selectionStart' property from 'HTMLInputElement'
// http://stackoverflow.com/q/21177489/3040605
}
});
},
updated() {
const { value, max, min } = this.$props;
const { focused } = this.$data;
const { prevProps } = this;
const props = getOptionProps(this);
// Don't trigger in componentDidMount
if (prevProps) {
if (
!isEqual(prevProps.value, value) ||
!isEqual(prevProps.max, max) ||
!isEqual(prevProps.min, min)
) {
const validValue = focused ? value : this.getValidValue(value);
let nextInputValue;
if (this.pressingUpOrDown) {
nextInputValue = validValue;
} else if (this.inputting) {
nextInputValue = this.rawInput;
} else {
nextInputValue = this.toPrecisionAsStep(validValue);
}
this.setState({
// eslint-disable-line
sValue: validValue,
inputValue: nextInputValue,
});
}
// Trigger onChange when max or min change
// https://github.com/ant-design/ant-design/issues/11574
const nextValue = 'value' in props ? value : this.sValue;
// ref: null < 20 === true
// https://github.com/ant-design/ant-design/issues/14277
if (
'max' in props &&
prevProps.max !== max &&
typeof nextValue === 'number' &&
nextValue > max
) {
this.$emit('change', max);
}
if (
'min' in props &&
prevProps.min !== min &&
typeof nextValue === 'number' &&
nextValue < min
) {
this.$emit('change', min);
}
}
this.prevProps = { ...props };
this.$nextTick(() => {
this.updatedFunc();
});
@ -132,33 +178,6 @@ export default {
beforeDestroy() {
this.stop();
},
watch: {
value(val) {
const value = this.focused ? val : this.getValidValue(val, this.min, this.max);
this.setState({
sValue: val,
inputValue: this.inputting ? value : this.toPrecisionAsStep(value),
});
},
max(val) {
const props = getOptionProps(this);
// Trigger onChange when max or min change
// https://github.com/ant-design/ant-design/issues/11574
const nextValue = 'value' in props ? props.value : this.sValue;
// ref: null < 20 === true
// https://github.com/ant-design/ant-design/issues/14277
if (typeof nextValue === 'number' && nextValue > val) {
this.__emit('change', val);
}
},
min(val) {
const props = getOptionProps(this);
const nextValue = 'value' in props ? props.value : this.sValue;
if (typeof nextValue === 'number' && nextValue < val) {
this.__emit('change', val);
}
},
},
methods: {
updatedFunc() {
const inputElem = this.$refs.inputRef;
@ -231,6 +250,8 @@ export default {
const ratio = this.getRatio(e);
this.down(e, ratio);
this.stop();
} else if (e.keyCode === KeyCode.ENTER) {
this.$emit('pressEnter', e);
}
// Trigger user key down
this.recordCursorPosition();
@ -248,9 +269,9 @@ export default {
if (this.focused) {
this.inputting = true;
}
const input = this.parser(this.getValueFromEvent(e));
this.setState({ inputValue: input });
this.$emit('change', this.toNumberWhenUserInput(input)); // valid number or invalid string
this.rawInput = this.parser(this.getValueFromEvent(e));
this.setState({ inputValue: this.rawInput });
this.$emit('change', this.toNumber(this.rawInput)); // valid number or invalid string
},
onFocus(...args) {
this.setState({
@ -258,17 +279,20 @@ export default {
});
this.$emit('focus', ...args);
},
onBlur(e, ...args) {
onBlur(...args) {
this.inputting = false;
this.setState({
focused: false,
});
const value = this.getCurrentValidValue(this.inputValue);
// todo
// e.persist() // fix https://github.com/react-component/input-number/issues/51
this.setValue(value, () => {
this.$emit('blur', e, ...args);
});
const newValue = this.setValue(value);
if (this.$listeners.blur) {
const originValue = this.$refs.inputRef.value;
const inputValue = this.getInputDisplayValue({ focused: false, sValue: newValue });
this.$refs.inputRef.value = inputValue;
this.$emit('blur', ...args);
this.$refs.inputRef.value = originValue;
}
},
getCurrentValidValue(value) {
let val = value;
@ -317,8 +341,14 @@ export default {
},
setValue(v, callback) {
// trigger onChange
const { precision } = this.$props;
const newValue = this.isNotCompleteNumber(parseFloat(v, 10)) ? null : parseFloat(v, 10);
const changed = newValue !== this.sValue || `${newValue}` !== `${this.inputValue}`; // https://github.com/ant-design/ant-design/issues/7363
const { sValue: value = null, inputValue = null } = this.$data;
// https://github.com/ant-design/ant-design/issues/7363
// https://github.com/ant-design/ant-design/issues/16622
const newValueInString =
typeof newValue === 'number' ? newValue.toFixed(precision) : `${newValue}`;
const changed = newValue !== value || newValueInString !== `${inputValue}`;
if (!hasProp(this, 'value')) {
this.setState(
{
@ -339,6 +369,7 @@ export default {
if (changed) {
this.$emit('change', newValue);
}
return newValue;
},
getPrecision(value) {
if (isValidProps(this.precision)) {
@ -357,7 +388,7 @@ export default {
// step={1.0} value={1.51}
// press +
// then value should be 2.51, rather than 2.5
// if this.props.precision is undefined
// if this.$props.precision is undefined
// https://github.com/react-component/input-number/issues/39
getMaxPrecision(currentValue, ratio = 1) {
if (isValidProps(this.precision)) {
@ -376,8 +407,8 @@ export default {
const precision = this.getMaxPrecision(currentValue, ratio);
return Math.pow(10, precision);
},
getInputDisplayValue() {
const { focused, inputValue, sValue } = this;
getInputDisplayValue(state) {
const { focused, inputValue, sValue } = state || this.$data;
let inputDisplayValue;
if (focused) {
inputDisplayValue = inputValue;
@ -389,7 +420,14 @@ export default {
inputDisplayValue = '';
}
return inputDisplayValue;
let inputDisplayValueFormat = this.formatWrapper(inputDisplayValue);
if (isValidProps(this.$props.decimalSeparator)) {
inputDisplayValueFormat = inputDisplayValueFormat
.toString()
.replace('.', this.$props.decimalSeparator);
}
return inputDisplayValueFormat;
},
recordCursorPosition() {
// Record position
@ -407,7 +445,12 @@ export default {
}
},
fixCaret(start, end) {
if (start === undefined || end === undefined || !this.input || !this.input.value) {
if (
start === undefined ||
end === undefined ||
!this.$refs.inputRef ||
!this.$refs.inputRef.value
) {
return;
}
@ -433,6 +476,14 @@ export default {
if (index === -1) return false;
const prevCursorPos = this.cursorBefore.length;
if (
this.lastKeyCode === KeyCode.DELETE &&
this.cursorBefore.charAt(prevCursorPos - 1) === str[0]
) {
this.fixCaret(prevCursorPos, prevCursorPos);
return true;
}
if (index + str.length === fullStr.length) {
this.fixCaret(index, index);
@ -463,9 +514,6 @@ export default {
formatWrapper(num) {
// http://2ality.com/2012/03/signedzero.html
// https://github.com/ant-design/ant-design/issues/9439
if (isNegativeZero(num)) {
return '-0';
}
if (this.formatter) {
return this.formatter(num);
}
@ -476,9 +524,6 @@ export default {
return num;
}
const precision = Math.abs(this.getMaxPrecision(num));
if (precision === 0) {
return num.toString();
}
if (!isNaN(precision)) {
return Number(num).toFixed(precision);
}
@ -494,48 +539,36 @@ export default {
);
},
toNumber(num) {
if (this.isNotCompleteNumber(num)) {
const { precision, autoFocus } = this.$props;
const { focused = autoFocus } = this;
// num.length > 16 => This is to prevent input of large numbers
const numberIsTooLarge = num && num.length > 16 && focused;
if (this.isNotCompleteNumber(num) || numberIsTooLarge) {
return num;
}
if (isValidProps(this.precision)) {
return Number(Number(num).toFixed(this.precision));
if (isValidProps(precision)) {
return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
}
return Number(num);
},
// '1.0' '1.00' => may be a inputing number
toNumberWhenUserInput(num) {
// num.length > 16 => prevent input large number will became Infinity
if ((/\.\d*0$/.test(num) || num.length > 16) && this.focused) {
return num;
}
return this.toNumber(num);
},
upStep(val, rat) {
const { step, min } = this;
const { step } = this;
const precisionFactor = this.getPrecisionFactor(val, rat);
const precision = Math.abs(this.getMaxPrecision(val, rat));
let result;
if (typeof val === 'number') {
result = ((precisionFactor * val + precisionFactor * step * rat) / precisionFactor).toFixed(
precision,
);
} else {
result = min === -Infinity ? step : min;
}
const result = (
(precisionFactor * val + precisionFactor * step * rat) /
precisionFactor
).toFixed(precision);
return this.toNumber(result);
},
downStep(val, rat) {
const { step, min } = this;
const { step } = this;
const precisionFactor = this.getPrecisionFactor(val, rat);
const precision = Math.abs(this.getMaxPrecision(val, rat));
let result;
if (typeof val === 'number') {
result = ((precisionFactor * val - precisionFactor * step * rat) / precisionFactor).toFixed(
precision,
);
} else {
result = min === -Infinity ? -step : min;
}
const result = (
(precisionFactor * val - precisionFactor * step * rat) /
precisionFactor
).toFixed(precision);
return this.toNumber(result);
},
stepFn(type, e, ratio = 1, recursive) {
@ -627,16 +660,7 @@ export default {
// focus state, show input value
// unfocus state, show valid value
let inputDisplayValue;
if (this.focused) {
inputDisplayValue = this.inputValue;
} else {
inputDisplayValue = this.toPrecisionAsStep(this.sValue);
}
if (inputDisplayValue === undefined || inputDisplayValue === null) {
inputDisplayValue = '';
}
const inputDisplayValue = this.getInputDisplayValue();
let upEvents;
let downEvents;
@ -661,12 +685,6 @@ export default {
mouseleave: this.stop,
};
}
let inputDisplayValueFormat = this.formatWrapper(inputDisplayValue);
if (isValidProps(this.decimalSeparator)) {
inputDisplayValueFormat = inputDisplayValueFormat
.toString()
.replace('.', this.decimalSeparator);
}
const isUpDisabled = !!upDisabledClass || disabled || readOnly;
const isDownDisabled = !!downDisabledClass || disabled || readOnly;
const {
@ -733,14 +751,12 @@ export default {
)}
</InputHandler>
</div>
<div
class={`${prefixCls}-input-wrap`}
role="spinbutton"
aria-valuemin={this.min}
aria-valuemax={this.max}
aria-valuenow={sValue}
>
<div class={`${prefixCls}-input-wrap`}>
<input
role="spinbutton"
aria-valuemin={this.min}
aria-valuemax={this.max}
aria-valuenow={sValue}
required={this.required}
type={this.type}
placeholder={this.placeholder}
@ -759,10 +775,11 @@ export default {
min={this.min}
step={this.step}
name={this.name}
title={this.title}
id={this.id}
onInput={this.onChange}
ref="inputRef"
value={inputDisplayValueFormat}
value={inputDisplayValue}
pattern={this.pattern}
/>
</div>