2018-04-04 04:04:49 +00:00
|
|
|
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 () {
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
|
2018-04-04 04:04:49 +00:00
|
|
|
function preventDefault (e) {
|
|
|
|
e.preventDefault()
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
|
2018-04-04 04:04:49 +00:00
|
|
|
function defaultParser (input) {
|
|
|
|
return input.replace(/[^\w\.-]+/g, '')
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* When click and hold on a button - the speed of auto changin the value.
|
|
|
|
*/
|
2018-04-04 04:04:49 +00:00
|
|
|
const SPEED = 200
|
2018-04-04 01:44:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* When click and hold on a button - the delay before auto changin the value.
|
|
|
|
*/
|
2018-04-04 04:04:49 +00:00
|
|
|
const DELAY = 600
|
2018-04-04 01:44:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*/
|
2018-04-04 04:04:49 +00:00
|
|
|
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,
|
|
|
|
}
|
2018-04-04 01:44:19 +00:00
|
|
|
|
2018-04-04 04:04:49 +00:00
|
|
|
export default {
|
|
|
|
name: 'InputNumber',
|
|
|
|
mixins: [BaseMixin],
|
|
|
|
model: {
|
|
|
|
prop: 'value',
|
|
|
|
event: 'change',
|
|
|
|
},
|
|
|
|
props: initDefaultProps(inputNumberProps, {
|
2018-04-04 01:44:19 +00:00
|
|
|
focusOnUpDown: true,
|
|
|
|
useTouch: false,
|
|
|
|
prefixCls: 'rc-input-number',
|
|
|
|
min: -MAX_SAFE_INTEGER,
|
|
|
|
step: 1,
|
|
|
|
parser: defaultParser,
|
|
|
|
required: false,
|
2018-04-04 04:04:49 +00:00
|
|
|
}),
|
|
|
|
data () {
|
|
|
|
let value
|
|
|
|
if (hasProp(this, 'value')) {
|
|
|
|
value = this.value
|
2018-04-04 01:44:19 +00:00
|
|
|
} else {
|
2018-04-04 04:04:49 +00:00
|
|
|
value = this.defaultValue
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
2018-04-04 04:04:49 +00:00
|
|
|
value = this.toNumber(value)
|
2018-04-04 01:44:19 +00:00
|
|
|
|
2018-04-04 04:04:49 +00:00
|
|
|
return {
|
2018-04-04 01:44:19 +00:00
|
|
|
inputValue: this.toPrecisionAsStep(value),
|
2018-04-04 04:04:49 +00:00
|
|
|
sValue: value,
|
|
|
|
focused: this.autoFocus,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
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
|
|
|
|
}
|
|
|
|
})
|
|
|
|
},
|
|
|
|
updated () {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
this.updatedFunc()
|
|
|
|
})
|
|
|
|
},
|
|
|
|
beforeDestroy () {
|
|
|
|
this.stop()
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
value (val) {
|
|
|
|
const value = this.focused
|
|
|
|
? val : this.getValidValue(val, this.min, this.max)
|
2018-04-04 01:44:19 +00:00
|
|
|
this.setState({
|
2018-04-04 04:04:49 +00:00
|
|
|
sValue: val,
|
2018-04-04 01:44:19 +00:00
|
|
|
inputValue: this.inputting ? value : this.toPrecisionAsStep(value),
|
2018-04-04 04:04:49 +00:00
|
|
|
})
|
|
|
|
},
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
updatedFunc () {
|
|
|
|
if (!this.pressingUpOrDown) {
|
|
|
|
return
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
2018-04-04 04:04:49 +00:00
|
|
|
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) {
|
2018-04-04 01:44:19 +00:00
|
|
|
this.setState({
|
2018-04-04 04:04:49 +00:00
|
|
|
focused: true,
|
|
|
|
})
|
|
|
|
this.$emit('focus', ...args)
|
|
|
|
},
|
|
|
|
onBlur (e, ...args) {
|
|
|
|
this.inputting = false
|
2018-04-04 01:44:19 +00:00
|
|
|
this.setState({
|
2018-04-04 04:04:49 +00:00
|
|
|
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
|
2018-04-04 01:44:19 +00:00
|
|
|
const classes = classNames({
|
|
|
|
[prefixCls]: true,
|
|
|
|
[`${prefixCls}-disabled`]: disabled,
|
2018-04-04 04:04:49 +00:00
|
|
|
[`${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`
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
2018-04-04 04:04:49 +00:00
|
|
|
if (val <= this.min) {
|
|
|
|
downDisabledClass = `${prefixCls}-handler-down-disabled`
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-04-04 04:04:49 +00:00
|
|
|
upDisabledClass = `${prefixCls}-handler-up-disabled`
|
|
|
|
downDisabledClass = `${prefixCls}-handler-down-disabled`
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-04 04:04:49 +00:00
|
|
|
const editable = !this.readOnly && !this.disabled
|
2018-04-04 01:44:19 +00:00
|
|
|
|
|
|
|
// focus state, show input value
|
|
|
|
// unfocus state, show valid value
|
2018-04-04 04:04:49 +00:00
|
|
|
let inputDisplayValue
|
|
|
|
if (this.focused) {
|
|
|
|
inputDisplayValue = this.inputValue
|
2018-04-04 01:44:19 +00:00
|
|
|
} else {
|
2018-04-04 04:04:49 +00:00
|
|
|
inputDisplayValue = this.toPrecisionAsStep(this.sValue)
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (inputDisplayValue === undefined || inputDisplayValue === null) {
|
2018-04-04 04:04:49 +00:00
|
|
|
inputDisplayValue = ''
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
|
2018-04-04 04:04:49 +00:00
|
|
|
let upEvents
|
|
|
|
let downEvents
|
2018-04-04 01:44:19 +00:00
|
|
|
if (useTouch) {
|
|
|
|
upEvents = {
|
2018-04-04 04:04:49 +00:00
|
|
|
touchstart: (editable && !upDisabledClass) ? this.up : noop,
|
|
|
|
touchend: this.stop,
|
|
|
|
}
|
2018-04-04 01:44:19 +00:00
|
|
|
downEvents = {
|
2018-04-04 04:04:49 +00:00
|
|
|
touchstart: (editable && !downDisabledClass) ? this.down : noop,
|
|
|
|
touchend: this.stop,
|
|
|
|
}
|
2018-04-04 01:44:19 +00:00
|
|
|
} else {
|
|
|
|
upEvents = {
|
2018-04-04 04:04:49 +00:00
|
|
|
mousedown: (editable && !upDisabledClass) ? this.up : noop,
|
|
|
|
mouseup: this.stop,
|
|
|
|
mouseleave: this.stop,
|
|
|
|
}
|
2018-04-04 01:44:19 +00:00
|
|
|
downEvents = {
|
2018-04-04 04:04:49 +00:00
|
|
|
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',
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|
|
|
|
// ref for test
|
|
|
|
return (
|
|
|
|
<div
|
2018-04-04 04:04:49 +00:00
|
|
|
{...contentProps}
|
2018-04-04 01:44:19 +00:00
|
|
|
>
|
2018-04-04 04:04:49 +00:00
|
|
|
<div class={`${prefixCls}-handler-wrap`}>
|
2018-04-04 01:44:19 +00:00
|
|
|
<InputHandler
|
2018-04-04 04:04:49 +00:00
|
|
|
{...upHandlerProps}
|
2018-04-04 01:44:19 +00:00
|
|
|
>
|
2018-04-04 04:04:49 +00:00
|
|
|
{this.upHandler || <span
|
|
|
|
unselectable='unselectable'
|
|
|
|
class={`${prefixCls}-handler-up-inner`}
|
2018-04-04 01:44:19 +00:00
|
|
|
onClick={preventDefault}
|
|
|
|
/>}
|
|
|
|
</InputHandler>
|
|
|
|
<InputHandler
|
2018-04-04 04:04:49 +00:00
|
|
|
{...downHandlerProps}
|
2018-04-04 01:44:19 +00:00
|
|
|
>
|
2018-04-04 04:04:49 +00:00
|
|
|
{this.downHandler || <span
|
|
|
|
unselectable='unselectable'
|
|
|
|
class={`${prefixCls}-handler-down-inner`}
|
2018-04-04 01:44:19 +00:00
|
|
|
onClick={preventDefault}
|
|
|
|
/>}
|
|
|
|
</InputHandler>
|
|
|
|
</div>
|
|
|
|
<div
|
2018-04-04 04:04:49 +00:00
|
|
|
class={`${prefixCls}-input-wrap`}
|
|
|
|
role='spinbutton'
|
|
|
|
aria-valuemin={this.min}
|
|
|
|
aria-valuemax={this.max}
|
|
|
|
aria-valuenow={sValue}
|
2018-04-04 01:44:19 +00:00
|
|
|
>
|
|
|
|
<input
|
2018-04-04 04:04:49 +00:00
|
|
|
required={this.required}
|
|
|
|
type={this.type}
|
|
|
|
placeholder={this.placeholder}
|
|
|
|
onClick={this.handleInputClick}
|
|
|
|
class={`${prefixCls}-input`}
|
|
|
|
tabIndex={this.tabIndex}
|
|
|
|
autoComplete='off'
|
2018-04-04 01:44:19 +00:00
|
|
|
onFocus={this.onFocus}
|
|
|
|
onBlur={this.onBlur}
|
2018-04-04 04:04:49 +00:00
|
|
|
onKeydown={editable ? this.onKeyDown : noop}
|
|
|
|
onKeyup={editable ? this.onKeyUp : noop}
|
|
|
|
autoFocus={this.autoFocus}
|
|
|
|
maxLength={this.maxLength}
|
|
|
|
readOnly={this.readOnly}
|
|
|
|
disabled={this.disabled}
|
|
|
|
max={this.max}
|
|
|
|
min={this.min}
|
|
|
|
step={this.step}
|
|
|
|
name={this.name}
|
|
|
|
id={this.id}
|
2018-04-04 01:44:19 +00:00
|
|
|
onChange={this.onChange}
|
2018-04-04 04:04:49 +00:00
|
|
|
ref='inputRef'
|
2018-04-04 01:44:19 +00:00
|
|
|
value={inputDisplayValueFormat}
|
2018-04-04 04:04:49 +00:00
|
|
|
pattern={this.pattern}
|
2018-04-04 01:44:19 +00:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</div>
|
2018-04-04 04:04:49 +00:00
|
|
|
)
|
|
|
|
},
|
2018-04-04 01:44:19 +00:00
|
|
|
}
|