diff --git a/components/vc-input-number/demo/combination-key-format.jsx b/components/vc-input-number/demo/combination-key-format.jsx
new file mode 100644
index 000000000..cb3cdd386
--- /dev/null
+++ b/components/vc-input-number/demo/combination-key-format.jsx
@@ -0,0 +1,56 @@
+import InputNumber from '../src/index'
+import '../assets/index.less'
+
+export default {
+ data () {
+ return {
+ disabled: false,
+ readOnly: false,
+ value: 50000,
+ }
+ },
+ methods: {
+ onChange (value) {
+ console.log('onChange:', value)
+ this.value = value
+ },
+ toggleDisabled () {
+ this.disabled = !this.disabled
+ },
+ toggleReadOnly () {
+ this.readOnly = !this.readOnly
+ },
+ numberWithCommas (x) {
+ return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
+ },
+ format (num) {
+ return `$ ${this.numberWithCommas(num)} boeing737`
+ },
+ parser (num) {
+ return num.toString().split(' ')[1].replace(/,*/g, '')
+ },
+ },
+ render () {
+ return (
+
+
+
+
+
+
+
+ )
+ },
+}
diff --git a/components/vc-input-number/demo/custom.jsx b/components/vc-input-number/demo/custom.jsx
new file mode 100644
index 000000000..4014ae019
--- /dev/null
+++ b/components/vc-input-number/demo/custom.jsx
@@ -0,0 +1,43 @@
+import InputNumber from '../src/index'
+import '../assets/index.less'
+
+export default {
+ data () {
+ return {
+ disabled: false,
+ readOnly: false,
+ value: 5,
+ }
+ },
+ methods: {
+ onChange (value) {
+ console.log('onChange:', value)
+ this.value = value
+ },
+ toggleDisabled () {
+ this.disabled = !this.disabled
+ },
+ toggleReadOnly () {
+ this.readOnly = !this.readOnly
+ },
+ },
+ render () {
+ const upHandler = (x
)
+ const downHandler = (V
)
+ return (
+
+
+
+ )
+ },
+}
diff --git a/components/vc-input-number/demo/precision.jsx b/components/vc-input-number/demo/precision.jsx
new file mode 100644
index 000000000..755a7e3a9
--- /dev/null
+++ b/components/vc-input-number/demo/precision.jsx
@@ -0,0 +1,38 @@
+import InputNumber from '../src/index'
+import '../assets/index.less'
+
+export default {
+ data () {
+ return {
+ precision: 2,
+ }
+ },
+ methods: {
+ onChange (value) {
+ console.log('onChange:', value)
+ this.value = value
+ },
+ changeprecision (e) {
+ this.precision = parseInt(e.target.value, 10)
+ },
+ },
+ render () {
+ return (
+
+ )
+ },
+}
diff --git a/components/vc-input-number/demo/simple-use-touch.jsx b/components/vc-input-number/demo/simple-use-touch.jsx
new file mode 100644
index 000000000..45886effd
--- /dev/null
+++ b/components/vc-input-number/demo/simple-use-touch.jsx
@@ -0,0 +1,44 @@
+import InputNumber from '../src/index'
+import '../assets/index.less'
+
+export default {
+ data () {
+ return {
+ disabled: false,
+ readOnly: false,
+ value: 5,
+ }
+ },
+ methods: {
+ onChange (value) {
+ console.log('onChange:', value)
+ this.value = value
+ },
+ toggleDisabled () {
+ this.disabled = !this.disabled
+ },
+ toggleReadOnly () {
+ this.readOnly = !this.readOnly
+ },
+ },
+ render () {
+ return (
+
+
+
+
+
+
+
+ )
+ },
+}
diff --git a/components/vc-input-number/demo/simple.jsx b/components/vc-input-number/demo/simple.jsx
new file mode 100644
index 000000000..0f9a89b81
--- /dev/null
+++ b/components/vc-input-number/demo/simple.jsx
@@ -0,0 +1,43 @@
+import InputNumber from '../src/index'
+import '../assets/index.less'
+
+export default {
+ data () {
+ return {
+ disabled: false,
+ readOnly: false,
+ value: 5,
+ }
+ },
+ methods: {
+ onChange (value) {
+ console.log('onChange:', value)
+ this.value = value
+ },
+ toggleDisabled () {
+ this.disabled = !this.disabled
+ },
+ toggleReadOnly () {
+ this.readOnly = !this.readOnly
+ },
+ },
+ render () {
+ return (
+
+
+
+
+
+
+
+ )
+ },
+}
diff --git a/components/vc-input-number/demo/small-step.jsx b/components/vc-input-number/demo/small-step.jsx
new file mode 100644
index 000000000..b4d4693c2
--- /dev/null
+++ b/components/vc-input-number/demo/small-step.jsx
@@ -0,0 +1,36 @@
+import InputNumber from '../src/index'
+import '../assets/index.less'
+
+export default {
+ data () {
+ return {
+ value: 0.000000001,
+ }
+ },
+ methods: {
+ onChange (value) {
+ console.log('onChange:', value)
+ this.value = value
+ },
+ toggleDisabled () {
+ this.disabled = !this.disabled
+ },
+ toggleReadOnly () {
+ this.readOnly = !this.readOnly
+ },
+ },
+ render () {
+ return (
+
+
+
+ )
+ },
+}
diff --git a/components/vc-input-number/src/InputHandler.js b/components/vc-input-number/src/InputHandler.js
index 2e079c5ca..15ee5b868 100755
--- a/components/vc-input-number/src/InputHandler.js
+++ b/components/vc-input-number/src/InputHandler.js
@@ -1,37 +1,33 @@
-import React, { Component } from 'react';
-import PropTypes from 'prop-types';
-import Touchable from 'rmc-feedback';
+import PropTypes from '../../_util/vue-types'
+import Touchable from '../../vc-m-feedback'
-class InputHandler extends Component {
- render() {
- const {
- prefixCls, disabled, onTouchStart, onTouchEnd,
- onMouseDown, onMouseUp, onMouseLeave, ...otherProps,
- } = this.props;
+const InputHandler = {
+ props: {
+ prefixCls: PropTypes.string,
+ disabled: PropTypes.bool,
+ },
+ render () {
+ const { prefixCls, disabled } = this.$props
+ const touchableProps = {
+ props: {
+ disabled,
+ activeClassName: `${prefixCls}-handler-active`,
+ },
+ on: this.$listeners,
+ }
+ const spanProps = {
+ attrs: this.$attrs,
+ }
return (
-
+
+ {this.$slots.default}
+
- );
- }
+ )
+ },
}
-InputHandler.propTypes = {
- prefixCls: PropTypes.string,
- disabled: PropTypes.bool,
- onTouchStart: PropTypes.func,
- onTouchEnd: PropTypes.func,
- onMouseDown: PropTypes.func,
- onMouseUp: PropTypes.func,
- onMouseLeave: PropTypes.func,
-};
-
-export default InputHandler;
+export default InputHandler
diff --git a/components/vc-input-number/src/index.js b/components/vc-input-number/src/index.js
index 293dc9270..6ad44864b 100755
--- a/components/vc-input-number/src/index.js
+++ b/components/vc-input-number/src/index.js
@@ -1,610 +1,590 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import isNegativeZero from 'is-negative-zero';
-import InputHandler from './InputHandler';
+import PropTypes from '../../_util/vue-types'
+import BaseMixin from '../../_util/BaseMixin'
+import { initDefaultProps, hasProp } from '../../_util/props-util'
+import classNames from 'classnames'
+import isNegativeZero from 'is-negative-zero'
+import InputHandler from './InputHandler'
-function noop() {
+function noop () {
}
-function preventDefault(e) {
- e.preventDefault();
+function preventDefault (e) {
+ e.preventDefault()
}
-function defaultParser(input) {
- return input.replace(/[^\w\.-]+/g, '');
+function defaultParser (input) {
+ return input.replace(/[^\w\.-]+/g, '')
}
/**
* When click and hold on a button - the speed of auto changin the value.
*/
-const SPEED = 200;
+const SPEED = 200
/**
* When click and hold on a button - the delay before auto changin the value.
*/
-const DELAY = 600;
+const DELAY = 600
/**
* Max Safe Integer -- on IE this is not available, so manually set the number in that case.
* The reason this is used, instead of Infinity is because numbers above the MSI are unstable
*/
-const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1;
+const MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || Math.pow(2, 53) - 1
+const inputNumberProps = {
+ value: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string,
+ ]),
+ defaultValue: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string,
+ ]),
+ focusOnUpDown: PropTypes.bool,
+ autoFocus: PropTypes.bool,
+ // onChange: PropTypes.func,
+ // onKeyDown: PropTypes.func,
+ // onKeyUp: PropTypes.func,
+ prefixCls: PropTypes.string,
+ tabIndex: PropTypes.string,
+ disabled: PropTypes.bool,
+ // onFocus: PropTypes.func,
+ // onBlur: PropTypes.func,
+ readOnly: PropTypes.bool,
+ max: PropTypes.number,
+ min: PropTypes.number,
+ step: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string,
+ ]),
+ upHandler: PropTypes.any,
+ downHandler: PropTypes.any,
+ useTouch: PropTypes.bool,
+ formatter: PropTypes.func,
+ parser: PropTypes.func,
+ // onMouseEnter: PropTypes.func,
+ // onMouseLeave: PropTypes.func,
+ // onMouseOver: PropTypes.func,
+ // onMouseOut: PropTypes.func,
+ precision: PropTypes.number,
+ required: PropTypes.bool,
+ pattern: PropTypes.string,
+}
-export default class InputNumber extends React.Component {
- static propTypes = {
- value: PropTypes.oneOfType([
- PropTypes.number,
- PropTypes.string,
- ]),
- defaultValue: PropTypes.oneOfType([
- PropTypes.number,
- PropTypes.string,
- ]),
- focusOnUpDown: PropTypes.bool,
- autoFocus: PropTypes.bool,
- onChange: PropTypes.func,
- onKeyDown: PropTypes.func,
- onKeyUp: PropTypes.func,
- prefixCls: PropTypes.string,
- tabIndex: PropTypes.string,
- disabled: PropTypes.bool,
- onFocus: PropTypes.func,
- onBlur: PropTypes.func,
- readOnly: PropTypes.bool,
- max: PropTypes.number,
- min: PropTypes.number,
- step: PropTypes.oneOfType([
- PropTypes.number,
- PropTypes.string,
- ]),
- upHandler: PropTypes.node,
- downHandler: PropTypes.node,
- useTouch: PropTypes.bool,
- formatter: PropTypes.func,
- parser: PropTypes.func,
- onMouseEnter: PropTypes.func,
- onMouseLeave: PropTypes.func,
- onMouseOver: PropTypes.func,
- onMouseOut: PropTypes.func,
- precision: PropTypes.number,
- required: PropTypes.bool,
- pattern: PropTypes.string,
- }
-
- static defaultProps = {
+export default {
+ name: 'InputNumber',
+ mixins: [BaseMixin],
+ model: {
+ prop: 'value',
+ event: 'change',
+ },
+ props: initDefaultProps(inputNumberProps, {
focusOnUpDown: true,
useTouch: false,
prefixCls: 'rc-input-number',
min: -MAX_SAFE_INTEGER,
step: 1,
- style: {},
- onChange: noop,
- onKeyDown: noop,
- onFocus: noop,
- onBlur: noop,
parser: defaultParser,
required: false,
- }
-
- constructor(props) {
- super(props);
-
- let value;
- if ('value' in props) {
- value = props.value;
+ }),
+ data () {
+ let value
+ if (hasProp(this, 'value')) {
+ value = this.value
} else {
- value = props.defaultValue;
+ value = this.defaultValue
}
- value = this.toNumber(value);
+ value = this.toNumber(value)
- this.state = {
+ return {
inputValue: this.toPrecisionAsStep(value),
- value,
- focused: props.autoFocus,
- };
- }
-
- componentDidMount() {
- this.componentDidUpdate();
- }
-
- componentWillReceiveProps(nextProps) {
- if ('value' in nextProps) {
- const value = this.state.focused
- ? nextProps.value : this.getValidValue(nextProps.value, nextProps.min, nextProps.max);
- this.setState({
- value,
- inputValue: this.inputting ? value : this.toPrecisionAsStep(value),
- });
+ sValue: value,
+ focused: this.autoFocus,
}
- }
-
- componentWillUpdate() {
- try {
- this.start = this.input.selectionStart;
- this.end = this.input.selectionEnd;
- } catch (e) {
- // Fix error in Chrome:
- // Failed to read the 'selectionStart' property from 'HTMLInputElement'
- // http://stackoverflow.com/q/21177489/3040605
- }
- }
-
- componentDidUpdate() {
- // pressingUpOrDown is true means that someone just click up or down button
- // https://github.com/ant-design/ant-design/issues/9204
- if (!this.pressingUpOrDown) {
- return;
- }
- if (this.props.focusOnUpDown && this.state.focused) {
- const selectionRange = this.input.setSelectionRange;
- if (selectionRange &&
- typeof selectionRange === 'function' &&
- this.start !== undefined &&
- this.end !== undefined) {
- this.input.setSelectionRange(this.start, this.end);
- } else {
- this.focus();
+ },
+ mounted () {
+ this.$nextTick(() => {
+ 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
}
- this.pressingUpOrDown = false;
- }
- }
-
- componentWillUnmount() {
- this.stop();
- }
-
- onKeyDown = (e, ...args) => {
- if (e.keyCode === 38) {
- const ratio = this.getRatio(e);
- this.up(e, ratio);
- this.stop();
- } else if (e.keyCode === 40) {
- const ratio = this.getRatio(e);
- this.down(e, ratio);
- this.stop();
- }
- const { onKeyDown } = this.props;
- if (onKeyDown) {
- onKeyDown(e, ...args);
- }
- }
-
- onKeyUp = (e, ...args) => {
- this.stop();
- const { onKeyUp } = this.props;
- if (onKeyUp) {
- onKeyUp(e, ...args);
- }
- }
-
- onChange = (e) => {
- if (this.state.focused) {
- this.inputting = true;
- }
- const input = this.props.parser(this.getValueFromEvent(e));
- this.setState({ inputValue: input });
- this.props.onChange(this.toNumberWhenUserInput(input)); // valid number or invalid string
- }
-
- onFocus = (...args) => {
- this.setState({
- focused: true,
- });
- this.props.onFocus(...args);
- }
-
- onBlur = (e, ...args) => {
- this.inputting = false;
- this.setState({
- focused: false,
- });
- const value = this.getCurrentValidValue(this.state.inputValue);
- e.persist(); // fix https://github.com/react-component/input-number/issues/51
- this.setValue(value, () => {
- this.props.onBlur(e, ...args);
- });
- }
-
- getCurrentValidValue(value) {
- let val = value;
- if (val === '') {
- val = '';
- } else if (!this.isNotCompleteNumber(val)) {
- val = this.getValidValue(val);
- } else {
- val = this.state.value;
- }
- return this.toNumber(val);
- }
-
- getRatio(e) {
- let ratio = 1;
- if (e.metaKey || e.ctrlKey) {
- ratio = 0.1;
- } else if (e.shiftKey) {
- ratio = 10;
- }
- return ratio;
- }
-
- getValueFromEvent(e) {
- // optimize for chinese input expierence
- // https://github.com/ant-design/ant-design/issues/8196
- return e.target.value.trim().replace(/。/g, '.');
- }
-
- getValidValue(value, min = this.props.min, max = this.props.max) {
- let val = parseFloat(value, 10);
- // https://github.com/ant-design/ant-design/issues/7358
- if (isNaN(val)) {
- return value;
- }
- if (val < min) {
- val = min;
- }
- if (val > max) {
- val = max;
- }
- return val;
- }
-
- setValue(v, callback) {
- // trigger onChange
- const newValue = this.isNotCompleteNumber(parseFloat(v, 10)) ? undefined : parseFloat(v, 10);
- const changed = newValue !== this.state.value ||
- `${newValue}` !== `${this.state.inputValue}`; // https://github.com/ant-design/ant-design/issues/7363
- if (!('value' in this.props)) {
+ })
+ },
+ updated () {
+ this.$nextTick(() => {
+ this.updatedFunc()
+ })
+ },
+ beforeDestroy () {
+ this.stop()
+ },
+ watch: {
+ value (val) {
+ const value = this.focused
+ ? val : this.getValidValue(val, this.min, this.max)
this.setState({
- value: newValue,
- inputValue: this.toPrecisionAsStep(v),
- }, callback);
- } else {
- // always set input value same as value
+ sValue: val,
+ inputValue: this.inputting ? value : this.toPrecisionAsStep(value),
+ })
+ },
+ },
+ methods: {
+ updatedFunc () {
+ if (!this.pressingUpOrDown) {
+ return
+ }
+ if (this.focusOnUpDown && this.focused) {
+ const selectionRange = this.$refs.inputRef.setSelectionRange
+ if (selectionRange &&
+ typeof selectionRange === 'function' &&
+ this.start !== undefined &&
+ this.end !== undefined) {
+ this.$refs.inputRef.setSelectionRange(this.start, this.end)
+ } else {
+ this.focus()
+ }
+ this.pressingUpOrDown = false
+ }
+ },
+ onKeyDown (e, ...args) {
+ if (e.keyCode === 38) {
+ const ratio = this.getRatio(e)
+ this.up(e, ratio)
+ this.stop()
+ } else if (e.keyCode === 40) {
+ const ratio = this.getRatio(e)
+ this.down(e, ratio)
+ this.stop()
+ }
+ this.$emit('keydown', e, ...args)
+ },
+ onKeyUp (e, ...args) {
+ this.stop()
+ this.$emit('keyup', e, ...args)
+ },
+ onChange (e) {
+ 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
+ },
+ onFocus (...args) {
this.setState({
- inputValue: this.toPrecisionAsStep(this.state.value),
- }, callback);
- }
- if (changed) {
- this.props.onChange(newValue);
- }
- }
-
- getPrecision(value) {
- if ('precision' in this.props) {
- return this.props.precision;
- }
- const valueString = value.toString();
- if (valueString.indexOf('e-') >= 0) {
- return parseInt(valueString.slice(valueString.indexOf('e-') + 2), 10);
- }
- let precision = 0;
- if (valueString.indexOf('.') >= 0) {
- precision = valueString.length - valueString.indexOf('.') - 1;
- }
- return precision;
- }
-
- // step={1.0} value={1.51}
- // press +
- // then value should be 2.51, rather than 2.5
- // if this.props.precision is undefined
- // https://github.com/react-component/input-number/issues/39
- getMaxPrecision(currentValue, ratio = 1) {
- if ('precision' in this.props) {
- return this.props.precision;
- }
- const { step } = this.props;
- const ratioPrecision = this.getPrecision(ratio);
- const stepPrecision = this.getPrecision(step);
- const currentValuePrecision = this.getPrecision(currentValue);
- if (!currentValue) {
- return ratioPrecision + stepPrecision;
- }
- return Math.max(currentValuePrecision, ratioPrecision + stepPrecision);
- }
-
- getPrecisionFactor(currentValue, ratio = 1) {
- const precision = this.getMaxPrecision(currentValue, ratio);
- return Math.pow(10, precision);
- }
-
- focus() {
- this.input.focus();
- }
-
- blur() {
- this.input.blur();
- }
-
- 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.props.formatter) {
- return this.props.formatter(num);
- }
- return num;
- }
-
- toPrecisionAsStep(num) {
- if (this.isNotCompleteNumber(num) || num === '') {
- return num;
- }
- const precision = Math.abs(this.getMaxPrecision(num));
- if (precision === 0) {
- return num.toString();
- }
- if (!isNaN(precision)) {
- return Number(num).toFixed(precision);
- }
- return num.toString();
- }
-
- // '1.' '1x' 'xx' '' => are not complete numbers
- isNotCompleteNumber(num) {
- return (
- isNaN(num) ||
- num === '' ||
- num === null ||
- (num && num.toString().indexOf('.') === num.toString().length - 1)
- );
- }
-
- toNumber(num) {
- if (this.isNotCompleteNumber(num)) {
- return num;
- }
- if ('precision' in this.props) {
- return Number(Number(num).toFixed(this.props.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.state.focused) {
- return num;
- }
- return this.toNumber(num);
- }
-
- upStep(val, rat) {
- const { step, min } = this.props;
- 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;
- }
- return this.toNumber(result);
- }
-
- downStep(val, rat) {
- const { step, min } = this.props;
- 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;
- }
- return this.toNumber(result);
- }
-
- step(type, e, ratio = 1, recursive) {
- this.stop();
- if (e) {
- e.persist();
- e.preventDefault();
- }
- const props = this.props;
- if (props.disabled) {
- return;
- }
- const value = this.getCurrentValidValue(this.state.inputValue) || 0;
- if (this.isNotCompleteNumber(value)) {
- return;
- }
- let val = this[`${type}Step`](value, ratio);
- const outOfRange = val > props.max || val < props.min;
- if (val > props.max) {
- val = props.max;
- } else if (val < props.min) {
- val = props.min;
- }
- this.setValue(val);
- this.setState({
- focused: true,
- });
- if (outOfRange) {
- return;
- }
- this.autoStepTimer = setTimeout(() => {
- this[type](e, ratio, true);
- }, recursive ? SPEED : DELAY);
- }
-
- stop = () => {
- if (this.autoStepTimer) {
- clearTimeout(this.autoStepTimer);
- }
- }
-
- down = (e, ratio, recursive) => {
- this.pressingUpOrDown = true;
- this.step('down', e, ratio, recursive);
- }
-
- up = (e, ratio, recursive) => {
- this.pressingUpOrDown = true;
- this.step('up', e, ratio, recursive);
- }
-
- saveInput = (node) => {
- this.input = node;
- }
-
- render() {
- const props = { ...this.props };
- const { prefixCls, disabled, readOnly, useTouch } = props;
+ focused: true,
+ })
+ this.$emit('focus', ...args)
+ },
+ onBlur (e, ...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)
+ })
+ },
+ getCurrentValidValue (value) {
+ let val = value
+ if (val === '') {
+ val = ''
+ } else if (!this.isNotCompleteNumber(val)) {
+ val = this.getValidValue(val)
+ } else {
+ val = this.sValue
+ }
+ return this.toNumber(val)
+ },
+ getRatio (e) {
+ let ratio = 1
+ if (e.metaKey || e.ctrlKey) {
+ ratio = 0.1
+ } else if (e.shiftKey) {
+ ratio = 10
+ }
+ return ratio
+ },
+ getValueFromEvent (e) {
+ // optimize for chinese input expierence
+ // https://github.com/ant-design/ant-design/issues/8196
+ return e.target.value.trim().replace(/。/g, '.')
+ },
+ getValidValue (value, min = this.min, max = this.max) {
+ let val = parseFloat(value, 10)
+ // https://github.com/ant-design/ant-design/issues/7358
+ if (isNaN(val)) {
+ return value
+ }
+ if (val < min) {
+ val = min
+ }
+ if (val > max) {
+ val = max
+ }
+ return val
+ },
+ setValue (v, callback) {
+ // trigger onChange
+ const newValue = this.isNotCompleteNumber(parseFloat(v, 10)) ? undefined : parseFloat(v, 10)
+ const changed = newValue !== this.sValue ||
+ `${newValue}` !== `${this.inputValue}` // https://github.com/ant-design/ant-design/issues/7363
+ if (!hasProp(this, 'value')) {
+ this.setState({
+ sValue: newValue,
+ inputValue: this.toPrecisionAsStep(v),
+ }, callback)
+ } else {
+ // always set input value same as value
+ this.setState({
+ inputValue: this.toPrecisionAsStep(this.sValue),
+ }, callback)
+ }
+ if (changed) {
+ this.$emit('change', newValue)
+ }
+ },
+ getPrecision (value) {
+ if (hasProp(this, 'precision')) {
+ return this.precision
+ }
+ const valueString = value.toString()
+ if (valueString.indexOf('e-') >= 0) {
+ return parseInt(valueString.slice(valueString.indexOf('e-') + 2), 10)
+ }
+ let precision = 0
+ if (valueString.indexOf('.') >= 0) {
+ precision = valueString.length - valueString.indexOf('.') - 1
+ }
+ return precision
+ },
+ // step={1.0} value={1.51}
+ // press +
+ // then value should be 2.51, rather than 2.5
+ // if this.props.precision is undefined
+ // https://github.com/react-component/input-number/issues/39
+ getMaxPrecision (currentValue, ratio = 1) {
+ if (hasProp(this, 'precision')) {
+ return this.precision
+ }
+ const { step } = this
+ const ratioPrecision = this.getPrecision(ratio)
+ const stepPrecision = this.getPrecision(step)
+ const currentValuePrecision = this.getPrecision(currentValue)
+ if (!currentValue) {
+ return ratioPrecision + stepPrecision
+ }
+ return Math.max(currentValuePrecision, ratioPrecision + stepPrecision)
+ },
+ getPrecisionFactor (currentValue, ratio = 1) {
+ const precision = this.getMaxPrecision(currentValue, ratio)
+ return Math.pow(10, precision)
+ },
+ focus () {
+ this.$refs.inputRef.focus()
+ },
+ blur () {
+ this.$refs.inputRef.blur()
+ },
+ 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)
+ }
+ return num
+ },
+ toPrecisionAsStep (num) {
+ if (this.isNotCompleteNumber(num) || num === '') {
+ return num
+ }
+ const precision = Math.abs(this.getMaxPrecision(num))
+ if (precision === 0) {
+ return num.toString()
+ }
+ if (!isNaN(precision)) {
+ return Number(num).toFixed(precision)
+ }
+ return num.toString()
+ },
+ // '1.' '1x' 'xx' '' => are not complete numbers
+ isNotCompleteNumber (num) {
+ return (
+ isNaN(num) ||
+ num === '' ||
+ num === null ||
+ (num && num.toString().indexOf('.') === num.toString().length - 1)
+ )
+ },
+ toNumber (num) {
+ if (this.isNotCompleteNumber(num)) {
+ return num
+ }
+ if (hasProp(this, 'precision')) {
+ return Number(Number(num).toFixed(this.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 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
+ }
+ return this.toNumber(result)
+ },
+ downStep (val, rat) {
+ const { step, min } = 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
+ }
+ return this.toNumber(result)
+ },
+ stepFn (type, e, ratio = 1, recursive) {
+ this.stop()
+ if (e) {
+ // e.persist()
+ e.preventDefault()
+ }
+ if (this.disabled) {
+ return
+ }
+ const { max, min } = this
+ const value = this.getCurrentValidValue(this.inputValue) || 0
+ if (this.isNotCompleteNumber(value)) {
+ return
+ }
+ let val = this[`${type}Step`](value, ratio)
+ const outOfRange = val > max || val < min
+ if (val > max) {
+ val = max
+ } else if (val < min) {
+ val = min
+ }
+ this.setValue(val)
+ this.setState({
+ focused: true,
+ })
+ if (outOfRange) {
+ return
+ }
+ this.autoStepTimer = setTimeout(() => {
+ this[type](e, ratio, true)
+ }, recursive ? SPEED : DELAY)
+ },
+ stop () {
+ if (this.autoStepTimer) {
+ clearTimeout(this.autoStepTimer)
+ }
+ },
+ down (e, ratio, recursive) {
+ this.pressingUpOrDown = true
+ this.stepFn('down', e, ratio, recursive)
+ },
+ up (e, ratio, recursive) {
+ this.pressingUpOrDown = true
+ this.stepFn('up', e, ratio, recursive)
+ },
+ handleInputClick () {
+ this.$emit('click')
+ },
+ },
+ render () {
+ const { prefixCls, disabled, readOnly, useTouch } = this.$props
const classes = classNames({
[prefixCls]: true,
- [props.className]: !!props.className,
[`${prefixCls}-disabled`]: disabled,
- [`${prefixCls}-focused`]: this.state.focused,
- });
- let upDisabledClass = '';
- let downDisabledClass = '';
- const { value } = this.state;
- if (value || value === 0) {
- if (!isNaN(value)) {
- const val = Number(value);
- if (val >= props.max) {
- upDisabledClass = `${prefixCls}-handler-up-disabled`;
+ [`${prefixCls}-focused`]: this.focused,
+ })
+ let upDisabledClass = ''
+ let downDisabledClass = ''
+ const { sValue } = this
+ if (sValue || sValue === 0) {
+ if (!isNaN(sValue)) {
+ const val = Number(sValue)
+ if (val >= this.max) {
+ upDisabledClass = `${prefixCls}-handler-up-disabled`
}
- if (val <= props.min) {
- downDisabledClass = `${prefixCls}-handler-down-disabled`;
+ if (val <= this.min) {
+ downDisabledClass = `${prefixCls}-handler-down-disabled`
}
} else {
- upDisabledClass = `${prefixCls}-handler-up-disabled`;
- downDisabledClass = `${prefixCls}-handler-down-disabled`;
+ upDisabledClass = `${prefixCls}-handler-up-disabled`
+ downDisabledClass = `${prefixCls}-handler-down-disabled`
}
}
- const editable = !props.readOnly && !props.disabled;
+ const editable = !this.readOnly && !this.disabled
// focus state, show input value
// unfocus state, show valid value
- let inputDisplayValue;
- if (this.state.focused) {
- inputDisplayValue = this.state.inputValue;
+ let inputDisplayValue
+ if (this.focused) {
+ inputDisplayValue = this.inputValue
} else {
- inputDisplayValue = this.toPrecisionAsStep(this.state.value);
+ inputDisplayValue = this.toPrecisionAsStep(this.sValue)
}
if (inputDisplayValue === undefined || inputDisplayValue === null) {
- inputDisplayValue = '';
+ inputDisplayValue = ''
}
- let upEvents;
- let downEvents;
+ let upEvents
+ let downEvents
if (useTouch) {
upEvents = {
- onTouchStart: (editable && !upDisabledClass) ? this.up : noop,
- onTouchEnd: this.stop,
- };
+ touchstart: (editable && !upDisabledClass) ? this.up : noop,
+ touchend: this.stop,
+ }
downEvents = {
- onTouchStart: (editable && !downDisabledClass) ? this.down : noop,
- onTouchEnd: this.stop,
- };
+ touchstart: (editable && !downDisabledClass) ? this.down : noop,
+ touchend: this.stop,
+ }
} else {
upEvents = {
- onMouseDown: (editable && !upDisabledClass) ? this.up : noop,
- onMouseUp: this.stop,
- onMouseLeave: this.stop,
- };
+ mousedown: (editable && !upDisabledClass) ? this.up : noop,
+ mouseup: this.stop,
+ mouseleave: this.stop,
+ }
downEvents = {
- onMouseDown: (editable && !downDisabledClass) ? this.down : noop,
- onMouseUp: this.stop,
- onMouseLeave: this.stop,
- };
+ mousedown: (editable && !downDisabledClass) ? this.down : noop,
+ mouseup: this.stop,
+ mouseleave: this.stop,
+ }
+ }
+ const inputDisplayValueFormat = this.formatWrapper(inputDisplayValue)
+ const isUpDisabled = !!upDisabledClass || disabled || readOnly
+ const isDownDisabled = !!downDisabledClass || disabled || readOnly
+ const contentProps = {
+ on: this.$listeners,
+ class: classes,
+ }
+ const upHandlerProps = {
+ props: {
+ disabled: isUpDisabled,
+ prefixCls,
+ },
+ attrs: {
+ unselectable: 'unselectable',
+ role: 'button',
+ 'aria-label': 'Increase Value',
+ 'aria-disabled': !!isUpDisabled,
+ },
+ class: `${prefixCls}-handler ${prefixCls}-handler-up ${upDisabledClass}`,
+ on: upEvents,
+ ref: 'up',
+ }
+ const downHandlerProps = {
+ props: {
+ disabled: isDownDisabled,
+ prefixCls,
+ },
+ attrs: {
+ unselectable: 'unselectable',
+ role: 'button',
+ 'aria-label': 'Decrease Value',
+ 'aria-disabled': !!isDownDisabled,
+ },
+ class: `${prefixCls}-handler ${prefixCls}-handler-down ${downDisabledClass}`,
+ on: downEvents,
+ ref: 'down',
}
- const inputDisplayValueFormat = this.formatWrapper(inputDisplayValue);
- const isUpDisabled = !!upDisabledClass || disabled || readOnly;
- const isDownDisabled = !!downDisabledClass || disabled || readOnly;
// ref for test
return (
-
+
- {this.props.upHandler || }
- {this.props.downHandler || }
- );
- }
+ )
+ },
}
diff --git a/examples/routes.js b/examples/routes.js
index 4b4388054..3d6bac0a1 100644
--- a/examples/routes.js
+++ b/examples/routes.js
@@ -3,11 +3,7 @@ const AsyncComp = () => {
const hashs = window.location.hash.split('/')
const d = hashs[hashs.length - 1]
return {
-<<<<<<< HEAD
- component: import(`../components/vc-m-feedback/demo/${d}`),
-=======
- component: import(`../components/table/demo/${d}`),
->>>>>>> 5d2271a131c74d672cc0cfada07e256752160b41
+ component: import(`../components/vc-input-number/demo/${d}`),
}
}
export default [
diff --git a/package.json b/package.json
index c5ae2dd47..9b08e686a 100644
--- a/package.json
+++ b/package.json
@@ -136,6 +136,7 @@
"dom-scroll-into-view": "^1.2.1",
"enquire.js": "^2.1.6",
"eslint-plugin-vue": "^3.13.0",
+ "is-negative-zero": "^2.0.0",
"lodash": "^4.17.5",
"moment": "^2.21.0",
"omit.js": "^1.0.0",