UNPKG

hongluan-ui

Version:
1 lines 17.3 kB
{"version":3,"file":"input-number2.mjs","sources":["../../../../../../packages/components/input-number/src/input-number.vue"],"sourcesContent":["<template>\n <div\n :class=\"[\n namespace + '-input-number',\n namespace + '-group',\n dir,\n merge ? 'merge' : '',\n deepMerge ? 'deep-merge' : '',\n indent ? 'indent' : '',\n round ? 'round' : '',\n block ? 'block' : '',\n inputNumberSize ? inputNumberSize : '',\n controlsPosition === 'inner' ? 'btn-inner' : '',\n { 'btn-vertical': ['left', 'right'].includes(controlsPosition) },\n { 'is-disabled': inputNumberDisabled },\n { 'is-without-controls': !controls },\n ]\"\n :style=\"[typeof indent === 'string' ? `--indent:${indent}` : '', typeof gap === 'string' ? `gap: ${gap}` : '']\"\n @dragstart.prevent\n >\n <hl-button\n v-if=\"(controls && 'initial' === controlsPosition) || 'inner' === controlsPosition\"\n v-repeat-click=\"decrease\"\n :class=\"['group-item', 'decrease', round ? 'round' : '', inputNumberFill ? 'light' : '']\"\n :size=\"inputNumberSize\"\n :disabled=\"minDisabled || inputNumberDisabled\"\n :aria-label=\"t('hl.inputNumber.decrease')\"\n >\n <slot name=\"icon-decrease\">\n <hl-icon>\n <system-remove />\n </hl-icon>\n </slot>\n </hl-button>\n <div\n v-if=\"controls && controlsPosition === 'left'\"\n :class=\"[namespace + '-group', 'btn-group', 'vertical', 'left', 'merge', 'indent']\"\n >\n <hl-button\n v-repeat-click=\"increase\"\n class=\"group-item increase\"\n :disabled=\"maxDisabled || inputNumberDisabled\"\n :size=\"inputNumberSize\"\n :aria-label=\"t('hl.inputNumber.increase')\"\n >\n <slot name=\"icon-increase\">\n <hl-icon>\n <system-arrow-up />\n </hl-icon>\n </slot>\n </hl-button>\n <hl-button\n v-repeat-click=\"decrease\"\n class=\"group-item decrease\"\n :disabled=\"minDisabled || inputNumberDisabled\"\n :size=\"inputNumberSize\"\n :aria-label=\"t('hl.inputNumber.decrease')\"\n >\n <slot name=\"icon-decrease\">\n <hl-icon>\n <system-arrow-down />\n </hl-icon>\n </slot>\n </hl-button>\n </div>\n <hl-input\n :id=\"id\"\n ref=\"input\"\n native-type=\"number\"\n class=\"group-item\"\n :validate-event=\"false\"\n :model-value=\"displayValue\"\n :step=\"step\"\n :placeholder=\"placeholder\"\n :readonly=\"readonly\"\n :disabled=\"inputNumberDisabled\"\n :size=\"inputNumberSize\"\n :max=\"max\"\n :min=\"min\"\n :name=\"name\"\n :aria-label=\"label || ariaLabel\"\n :fill=\"inputNumberFill\"\n :round=\"round\"\n @keydown.up.prevent=\"increase\"\n @keydown.down.prevent=\"decrease\"\n @blur=\"handleBlur\"\n @focus=\"handleFocus\"\n @input=\"handleInput\"\n @change=\"handleInputChange\"\n >\n <template v-if=\"$slots.prefix\" #prefix>\n <slot name=\"prefix\"></slot>\n </template>\n <template v-if=\"$slots.suffix\" #suffix>\n <slot name=\"suffix\"></slot>\n </template>\n </hl-input>\n <div\n v-if=\"controls && controlsPosition === 'right'\"\n :class=\"[namespace + '-group', 'btn-group', 'vertical', 'right', 'merge', 'indent']\"\n >\n <hl-button\n v-repeat-click=\"increase\"\n class=\"group-item increase\"\n :disabled=\"maxDisabled || inputNumberDisabled\"\n :size=\"inputNumberSize\"\n :aria-label=\"t('hl.inputNumber.increase')\"\n >\n <slot name=\"icon-increase\">\n <hl-icon>\n <system-arrow-up />\n </hl-icon>\n </slot>\n </hl-button>\n <hl-button\n v-repeat-click=\"decrease\"\n class=\"group-item decrease\"\n :disabled=\"minDisabled || inputNumberDisabled\"\n :size=\"inputNumberSize\"\n :aria-label=\"t('hl.inputNumber.decrease')\"\n >\n <slot name=\"icon-increase\">\n <hl-icon>\n <system-arrow-down />\n </hl-icon>\n </slot>\n </hl-button>\n </div>\n <hl-button\n v-if=\"(controls && 'initial' === controlsPosition) || 'inner' === controlsPosition\"\n v-repeat-click=\"increase\"\n :class=\"['group-item', 'increase', round ? 'round' : '', inputNumberFill ? 'light' : '']\"\n :size=\"inputNumberSize\"\n :disabled=\"maxDisabled || inputNumberDisabled\"\n :aria-label=\"t('hl.inputNumber.increase')\"\n >\n <slot name=\"icon-increase\">\n <hl-icon>\n <system-add />\n </hl-icon>\n </slot>\n </hl-button>\n </div>\n</template>\n\n<script lang=\"ts\" setup>\nimport { computed, inject, onMounted, onUpdated, reactive, ref, watch } from 'vue'\nimport { isNil } from 'lodash-unified'\nimport { vRepeatClick } from '@hongluan-ui/directives'\nimport HlInput from '@hongluan-ui/components/input'\nimport HlButton from '@hongluan-ui/components/button'\nimport HlIcon from '@hongluan-ui/components/icon'\nimport { SystemAdd, SystemRemove, SystemArrowDown, SystemArrowUp } from '@hongluan-ui/components/system-icon'\nimport {\n useLocale,\n useNamespace,\n useConsistentProp,\n} from '@hongluan-ui/hooks'\nimport { formItemContextKey, FormItemEvents } from '@hongluan-ui/tokens'\nimport { debugWarn, isNumber, isString, isUndefined, throwError } from '@hongluan-ui/utils'\nimport {\n CHANGE_EVENT,\n INPUT_EVENT,\n UPDATE_MODEL_EVENT,\n} from '@hongluan-ui/constants'\nimport { inputNumberEmits, inputNumberProps } from './input-number'\n\nimport type { InputInstance } from '@hongluan-ui/components/input'\nimport type { FormItemContext } from '@hongluan-ui/tokens'\n\ndefineOptions({\n name: 'InputNumber',\n})\n\nconst props = defineProps(inputNumberProps)\nconst emit = defineEmits(inputNumberEmits)\n\nconst { t } = useLocale()\nconst { namespace } = useNamespace()\nconst input = ref<InputInstance>()\n\ninterface Data {\n currentValue: number | null | undefined\n userInput: null | number | string\n}\nconst data = reactive<Data>({\n currentValue: props.modelValue,\n userInput: null,\n})\n\nconst formItem = inject(formItemContextKey, {} as FormItemContext)\n\nconst minDisabled = computed(\n () => isNumber(props.modelValue) && props.modelValue <= props.min,\n)\nconst maxDisabled = computed(\n () => isNumber(props.modelValue) && props.modelValue >= props.max,\n)\n\nconst numPrecision = computed(() => {\n const stepPrecision = getPrecision(props.step)\n if (!isUndefined(props.precision)) {\n if (stepPrecision > props.precision) {\n debugWarn(\n 'InputNumber',\n 'precision should not be less than the decimal places of step',\n )\n }\n return props.precision\n } else {\n return Math.max(getPrecision(props.modelValue), stepPrecision)\n }\n})\n\nconst { size: inputNumberSize, disabled: inputNumberDisabled, fill: inputNumberFill } = useConsistentProp()\n\nconst displayValue = computed(() => {\n if (data.userInput !== null) {\n return data.userInput\n }\n let currentValue: number | string | undefined | null = data.currentValue\n if (isNil(currentValue)) return ''\n if (isNumber(currentValue)) {\n if (Number.isNaN(currentValue)) return ''\n if (!isUndefined(props.precision)) {\n currentValue = currentValue.toFixed(props.precision)\n }\n }\n return currentValue\n})\nconst toPrecision = (num: number, pre?: number) => {\n if (isUndefined(pre)) pre = numPrecision.value\n if (pre === 0) return Math.round(num)\n let snum = String(num)\n const pointPos = snum.indexOf('.')\n if (pointPos === -1) return num\n const nums = snum.replace('.', '').split('')\n const datum = nums[pointPos + pre]\n if (!datum) return num\n const length = snum.length\n if (snum.charAt(length - 1) === '5') {\n snum = `${snum.slice(0, Math.max(0, length - 1))}6`\n }\n return Number.parseFloat(Number(snum).toFixed(pre))\n}\nconst getPrecision = (value: number | null | undefined) => {\n if (isNil(value)) return 0\n const valueString = value.toString()\n const dotPosition = valueString.indexOf('.')\n let precision = 0\n if (dotPosition !== -1) {\n precision = valueString.length - dotPosition - 1\n }\n return precision\n}\nconst ensurePrecision = (val: number, coefficient: 1 | -1 = 1) => {\n if (!isNumber(val)) return data.currentValue\n // Solve the accuracy problem of JS decimal calculation by converting the value to integer.\n return toPrecision(val + props.step * coefficient)\n}\nconst increase = () => {\n if (props.readonly || inputNumberDisabled.value || maxDisabled.value) return\n const value = Number(displayValue.value) || 0\n const newVal = ensurePrecision(value)\n setCurrentValue(newVal)\n emit(INPUT_EVENT, data.currentValue)\n setCurrentValueToModelValue()\n}\nconst decrease = () => {\n if (props.readonly || inputNumberDisabled.value || minDisabled.value) return\n const value = Number(displayValue.value) || 0\n const newVal = ensurePrecision(value, -1)\n setCurrentValue(newVal)\n emit(INPUT_EVENT, data.currentValue)\n setCurrentValueToModelValue()\n}\nconst verifyValue = (\n value: number | string | null | undefined,\n update?: boolean,\n): number | null | undefined => {\n const { max, min, step, precision, stepStrictly, valueOnClear } = props\n if (max < min) {\n throwError('InputNumber', 'min should not be greater than max.')\n }\n let newVal = Number(value)\n if (isNil(value) || Number.isNaN(newVal)) {\n return null\n }\n if (value === '') {\n if (valueOnClear === null) {\n return null\n }\n newVal = isString(valueOnClear) ? { min, max }[valueOnClear] : valueOnClear\n }\n if (stepStrictly) {\n newVal = toPrecision(Math.round(newVal / step) * step, precision)\n }\n if (!isUndefined(precision)) {\n newVal = toPrecision(newVal, precision)\n }\n if (newVal > max || newVal < min) {\n newVal = newVal > max ? max : min\n update && emit(UPDATE_MODEL_EVENT, newVal)\n }\n return newVal\n}\nconst setCurrentValue = (\n value: number | string | null | undefined,\n emitChange = true,\n) => {\n const oldVal = data.currentValue\n const newVal = verifyValue(value)\n if (!emitChange) {\n emit(UPDATE_MODEL_EVENT, newVal!)\n return\n }\n if (oldVal === newVal && value) return\n data.userInput = null\n emit(UPDATE_MODEL_EVENT, newVal!)\n if (oldVal !== newVal) {\n emit(CHANGE_EVENT, newVal!, oldVal!)\n }\n if (props.validateEvent) {\n formItem?.validate?.('change').catch(err => debugWarn(err))\n }\n data.currentValue = newVal\n}\nconst handleInput = (value: string) => {\n data.userInput = value\n const newVal = value === '' ? null : Number(value)\n emit(INPUT_EVENT, newVal)\n setCurrentValue(newVal, false)\n}\nconst handleInputChange = (value: string) => {\n const newVal = value !== '' ? Number(value) : ''\n if ((isNumber(newVal) && !Number.isNaN(newVal)) || value === '') {\n setCurrentValue(newVal)\n }\n setCurrentValueToModelValue()\n data.userInput = null\n}\n\nconst focus = () => {\n input.value?.focus?.()\n}\n\nconst blur = () => {\n input.value?.blur?.()\n}\n\nconst handleFocus = (event: MouseEvent | FocusEvent) => {\n emit('focus', event)\n}\n\nconst handleBlur = (event: MouseEvent | FocusEvent) => {\n data.userInput = null\n emit('blur', event)\n if (props.validateEvent) {\n formItem?.validate?.(FormItemEvents.blur).catch(err => debugWarn(err))\n }\n}\n\nconst setCurrentValueToModelValue = () => {\n if (data.currentValue !== props.modelValue) {\n data.currentValue = props.modelValue\n }\n}\nconst handleWheel = (e: WheelEvent) => {\n if (document.activeElement === e.target) e.preventDefault()\n}\n\nwatch(\n () => props.modelValue,\n (value, oldValue) => {\n const newValue = verifyValue(value, true)\n if (data.userInput === null && newValue !== oldValue) {\n data.currentValue = newValue\n }\n },\n { immediate: true },\n)\nonMounted(() => {\n const { min, max, modelValue } = props\n const innerInput = input.value?.input as HTMLInputElement\n innerInput.setAttribute('role', 'spinbutton')\n if (Number.isFinite(max)) {\n innerInput.setAttribute('aria-valuemax', String(max))\n } else {\n innerInput.removeAttribute('aria-valuemax')\n }\n if (Number.isFinite(min)) {\n innerInput.setAttribute('aria-valuemin', String(min))\n } else {\n innerInput.removeAttribute('aria-valuemin')\n }\n innerInput.setAttribute(\n 'aria-valuenow',\n data.currentValue || data.currentValue === 0\n ? String(data.currentValue)\n : '',\n )\n innerInput.setAttribute('aria-disabled', String(inputNumberDisabled.value))\n if (!isNumber(modelValue) && modelValue != null) {\n let val: number | null = Number(modelValue)\n if (Number.isNaN(val)) {\n val = null\n }\n emit(UPDATE_MODEL_EVENT, val!)\n }\n innerInput.addEventListener('wheel', handleWheel, { passive: false })\n})\nonUpdated(() => {\n const innerInput = input.value?.input\n innerInput?.setAttribute('aria-valuenow', `${data.currentValue ?? ''}`)\n})\ndefineExpose({\n increase,\n decrease,\n /** @description get focus the input component */\n focus,\n /** @description remove focus the input component */\n blur,\n})\n</script>\n"],"names":[],"mappings":"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"}