UNPKG

element-plus

Version:

A Component Library for Vue3.0

331 lines (323 loc) 12.7 kB
import { defineComponent, inject, ref, reactive, computed, watch, onMounted, onUpdated, resolveComponent, resolveDirective, openBlock, createBlock, withModifiers, withDirectives, withKeys, createVNode, createCommentVNode } from 'vue'; import { RepeatClick } from '../directives'; import ElInput from '../el-input'; import { useGlobalConfig } from '../utils/util'; import { isValidComponentSize } from '../utils/validators'; import { elFormKey, elFormItemKey } from '../el-form'; /** * Make a map and return a function for checking if a key * is in that map. * IMPORTANT: all calls of this function must be prefixed with * \/\*#\_\_PURE\_\_\*\/ * So that rollup can tree-shake them if necessary. */ const EMPTY_OBJ = (process.env.NODE_ENV !== 'production') ? Object.freeze({}) : {}; const EMPTY_ARR = (process.env.NODE_ENV !== 'production') ? Object.freeze([]) : []; const objectToString = Object.prototype.toString; const toTypeString = (value) => objectToString.call(value); const toRawType = (value) => { // extract "RawType" from strings like "[object RawType]" return toTypeString(value).slice(8, -1); }; var script = defineComponent({ name: 'ElInputNumber', components: { ElInput, }, directives: { RepeatClick, }, props: { step: { type: Number, default: 1, }, stepStrictly: { type: Boolean, default: false, }, max: { type: Number, default: Infinity, }, min: { type: Number, default: -Infinity, }, modelValue: { required: true, validator: val => { return toRawType(val) === 'Number' || val === undefined; }, }, disabled: { type: Boolean, default: false, }, size: { type: String, validator: isValidComponentSize, }, controls: { type: Boolean, default: true, }, controlsPosition: { type: String, default: '', }, name: String, label: String, placeholder: String, precision: { type: Number, validator: (val) => val >= 0 && val === parseInt(val + '', 10), }, }, emits: ['update:modelValue', 'change', 'input', 'blur', 'focus'], setup(props, { emit }) { const ELEMENT = useGlobalConfig(); const elForm = inject(elFormKey, {}); const elFormItem = inject(elFormItemKey, {}); const input = ref(null); const data = reactive({ currentValue: props.modelValue, userInput: null, }); const minDisabled = computed(() => { return _decrease(props.modelValue) < props.min; }); const maxDisabled = computed(() => { return _increase(props.modelValue) > props.max; }); const numPrecision = computed(() => { const stepPrecision = getPrecision(props.step); if (props.precision !== undefined) { if (stepPrecision > props.precision) { console.warn('[Element Warn][InputNumber]precision should not be less than the decimal places of step'); } return props.precision; } else { return Math.max(getPrecision(props.modelValue), stepPrecision); } }); const controlsAtRight = computed(() => { return props.controls && props.controlsPosition === 'right'; }); const inputNumberSize = computed(() => { return props.size || elFormItem.size || ELEMENT.size; }); const inputNumberDisabled = computed(() => { return props.disabled || elForm.disabled; }); const displayValue = computed(() => { if (data.userInput !== null) { return data.userInput; } let currentValue = data.currentValue; if (typeof currentValue === 'number') { if (props.precision !== undefined) { currentValue = currentValue.toFixed(props.precision); } } return currentValue; }); const toPrecision = (num, pre) => { if (pre === undefined) pre = numPrecision.value; return parseFloat(Math.round(num * Math.pow(10, pre)) / Math.pow(10, pre) + ''); }; const getPrecision = value => { if (value === undefined) return 0; const valueString = value.toString(); const dotPosition = valueString.indexOf('.'); let precision = 0; if (dotPosition !== -1) { precision = valueString.length - dotPosition - 1; } return precision; }; const _increase = val => { if (typeof val !== 'number' && val !== undefined) return data.currentValue; const precisionFactor = Math.pow(10, numPrecision.value); return toPrecision((precisionFactor * val + precisionFactor * props.step) / precisionFactor); }; const _decrease = val => { if (typeof val !== 'number' && val !== undefined) return data.currentValue; const precisionFactor = Math.pow(10, numPrecision.value); return toPrecision((precisionFactor * val - precisionFactor * props.step) / precisionFactor); }; const increase = () => { if (inputNumberDisabled.value || maxDisabled.value) return; const value = props.modelValue || 0; const newVal = _increase(value); setCurrentValue(newVal); }; const decrease = () => { if (inputNumberDisabled.value || minDisabled.value) return; const value = props.modelValue || 0; const newVal = _decrease(value); setCurrentValue(newVal); }; const setCurrentValue = newVal => { const oldVal = data.currentValue; if (typeof newVal === 'number' && props.precision !== undefined) { newVal = toPrecision(newVal, props.precision); } if (newVal !== undefined && newVal >= props.max) newVal = props.max; if (newVal !== undefined && newVal <= props.min) newVal = props.min; if (oldVal === newVal) return; data.userInput = null; emit('update:modelValue', newVal); emit('input', newVal); emit('change', newVal, oldVal); data.currentValue = newVal; }; const handleInput = value => { return (data.userInput = value); }; const handleInputChange = value => { const newVal = value === '' ? undefined : Number(value); if (!isNaN(newVal) || value === '') { setCurrentValue(newVal); } data.userInput = null; }; watch(() => props.modelValue, value => { let newVal = value === undefined ? value : Number(value); if (newVal !== undefined) { if (isNaN(newVal)) return; if (props.stepStrictly) { const stepPrecision = getPrecision(props.step); const precisionFactor = Math.pow(10, stepPrecision); newVal = (Math.round(newVal / props.step) * precisionFactor * props.step) / precisionFactor; } if (props.precision !== undefined) { newVal = toPrecision(newVal, props.precision); } } if (newVal !== undefined && newVal >= props.max) { newVal = props.max; emit('update:modelValue', newVal); } if (newVal !== undefined && newVal <= props.min) { newVal = props.min; emit('update:modelValue', newVal); } data.currentValue = newVal; data.userInput = null; }, { immediate: true }); onMounted(() => { let innerInput = input.value.input; innerInput.setAttribute('role', 'spinbutton'); innerInput.setAttribute('aria-valuemax', props.max); innerInput.setAttribute('aria-valuemin', props.min); innerInput.setAttribute('aria-valuenow', data.currentValue); innerInput.setAttribute('aria-disabled', inputNumberDisabled.value); if (toRawType(props.modelValue) !== 'Number' && props.modelValue !== undefined) { emit('update:modelValue', undefined); } }); onUpdated(() => { let innerInput = input.value.input; innerInput.setAttribute('aria-valuenow', data.currentValue); }); return { input, displayValue, handleInput, handleInputChange, controlsAtRight, decrease, increase, inputNumberSize, inputNumberDisabled, maxDisabled, minDisabled, }; }, }); function render(_ctx, _cache, $props, $setup, $data, $options) { const _component_el_input = resolveComponent("el-input"); const _directive_repeat_click = resolveDirective("repeat-click"); return (openBlock(), createBlock("div", { class: [ 'el-input-number', _ctx.inputNumberSize ? 'el-input-number--' + _ctx.inputNumberSize : '', { 'is-disabled': _ctx.inputNumberDisabled }, { 'is-without-controls': !_ctx.controls }, { 'is-controls-right': _ctx.controlsAtRight }, ], onDragstart: _cache[5] || (_cache[5] = withModifiers(() => {}, ["prevent"])) }, [ (_ctx.controls) ? withDirectives((openBlock(), createBlock("span", { key: 0, class: ["el-input-number__decrease", { 'is-disabled': _ctx.minDisabled }], role: "button", onKeydown: _cache[1] || (_cache[1] = withKeys((...args) => (_ctx.decrease && _ctx.decrease(...args)), ["enter"])) }, [ createVNode("i", { class: `el-icon-${_ctx.controlsAtRight ? 'arrow-down' : 'minus'}` }, null, 2 /* CLASS */) ], 34 /* CLASS, HYDRATE_EVENTS */)), [ [_directive_repeat_click, _ctx.decrease] ]) : createCommentVNode("v-if", true), (_ctx.controls) ? withDirectives((openBlock(), createBlock("span", { key: 1, class: ["el-input-number__increase", { 'is-disabled': _ctx.maxDisabled }], role: "button", onKeydown: _cache[2] || (_cache[2] = withKeys((...args) => (_ctx.increase && _ctx.increase(...args)), ["enter"])) }, [ createVNode("i", { class: `el-icon-${_ctx.controlsAtRight ? 'arrow-up' : 'plus'}` }, null, 2 /* CLASS */) ], 34 /* CLASS, HYDRATE_EVENTS */)), [ [_directive_repeat_click, _ctx.increase] ]) : createCommentVNode("v-if", true), createVNode(_component_el_input, { ref: "input", "model-value": _ctx.displayValue, placeholder: _ctx.placeholder, disabled: _ctx.inputNumberDisabled, size: _ctx.inputNumberSize, max: _ctx.max, min: _ctx.min, name: _ctx.name, label: _ctx.label, onKeydown: [ withKeys(withModifiers(_ctx.increase, ["prevent"]), ["up"]), withKeys(withModifiers(_ctx.decrease, ["prevent"]), ["down"]) ], onBlur: _cache[3] || (_cache[3] = event => _ctx.$emit('blur', event)), onFocus: _cache[4] || (_cache[4] = event => _ctx.$emit('focus', event)), onInput: _ctx.handleInput, onChange: _ctx.handleInputChange }, null, 8 /* PROPS */, ["model-value", "placeholder", "disabled", "size", "max", "min", "name", "label", "onKeydown", "onInput", "onChange"]) ], 34 /* CLASS, HYDRATE_EVENTS */)) } script.render = render; script.__file = "packages/input-number/src/index.vue"; script.install = (app) => { app.component(script.name, script); }; const _InputNumber = script; export default _InputNumber;