import type { PropType, ExtractPropTypes, HTMLAttributes, App } from 'vue'; import { watch, defineComponent, nextTick, onMounted, ref } from 'vue'; import classNames from '../_util/classNames'; import UpOutlined from '@ant-design/icons-vue/UpOutlined'; import DownOutlined from '@ant-design/icons-vue/DownOutlined'; import VcInputNumber, { inputNumberProps as baseInputNumberProps } from './src/InputNumber'; import type { SizeType } from '../config-provider'; import { useInjectFormItemContext } from '../form/FormItemContext'; import useConfigInject from '../_util/hooks/useConfigInject'; import { cloneElement } from '../_util/vnode'; import omit from '../_util/omit'; import PropTypes from '../_util/vue-types'; import isValidValue from '../_util/isValidValue'; const baseProps = baseInputNumberProps(); export const inputNumberProps = () => ({ ...baseProps, size: { type: String as PropType }, bordered: { type: Boolean, default: true }, placeholder: String, name: String, id: String, type: String, addonBefore: PropTypes.any, addonAfter: PropTypes.any, prefix: PropTypes.any, 'update:value': baseProps.onChange, }); export type InputNumberProps = Partial>>; const InputNumber = defineComponent({ name: 'AInputNumber', inheritAttrs: false, props: inputNumberProps(), // emits: ['focus', 'blur', 'change', 'input', 'update:value'], slots: ['addonBefore', 'addonAfter', 'prefix'], setup(props, { emit, expose, attrs, slots }) { const formItemContext = useInjectFormItemContext(); const { prefixCls, size, direction } = useConfigInject('input-number', props); const mergedValue = ref(props.value === undefined ? props.defaultValue : props.value); const focused = ref(false); watch( () => props.value, () => { mergedValue.value = props.value; }, ); const inputNumberRef = ref(null); const focus = () => { inputNumberRef.value?.focus(); }; const blur = () => { inputNumberRef.value?.blur(); }; expose({ focus, blur, }); const handleChange = (val: number) => { if (props.value === undefined) { mergedValue.value = val; } emit('update:value', val); emit('change', val); formItemContext.onFieldChange(); }; const handleBlur = (e: FocusEvent) => { focused.value = false; emit('blur', e); formItemContext.onFieldBlur(); }; const handleFocus = (e: FocusEvent) => { focused.value = true; emit('focus', e); }; onMounted(() => { nextTick(() => { if (process.env.NODE_ENV === 'test') { if (props.autofocus && !props.disabled) { focus(); } } }); }); return () => { const { class: className, bordered, readonly, style, addonBefore = slots.addonBefore?.(), addonAfter = slots.addonAfter?.(), prefix = slots.prefix?.(), ...others } = { ...(attrs as HTMLAttributes), ...props }; const preCls = prefixCls.value; const mergeSize = size.value; const inputNumberClass = classNames( { [`${preCls}-lg`]: mergeSize === 'large', [`${preCls}-sm`]: mergeSize === 'small', [`${preCls}-rtl`]: direction.value === 'rtl', [`${preCls}-readonly`]: readonly, [`${preCls}-borderless`]: !bordered, }, className, ); let element = ( , downHandler: () => , }} /> ); const hasAddon = isValidValue(addonBefore) || isValidValue(addonAfter); if (isValidValue(prefix)) { const affixWrapperCls = classNames(`${preCls}-affix-wrapper`, { [`${preCls}-affix-wrapper-focused`]: focused.value, [`${preCls}-affix-wrapper-disabled`]: props.disabled, [`${preCls}-affix-wrapper-sm`]: size.value === 'small', [`${preCls}-affix-wrapper-lg`]: size.value === 'large', [`${preCls}-affix-wrapper-rtl`]: direction.value === 'rtl', [`${preCls}-affix-wrapper-readonly`]: readonly, [`${preCls}-affix-wrapper-borderless`]: !bordered, // className will go to addon wrapper [`${className}`]: !hasAddon && className, }); element = ( inputNumberRef.value!.focus()} > {prefix} {element} ); } if (hasAddon) { const wrapperClassName = `${preCls}-group`; const addonClassName = `${wrapperClassName}-addon`; const addonBeforeNode = addonBefore ? ( {addonBefore} ) : null; const addonAfterNode = addonAfter ? {addonAfter} : null; const mergedWrapperClassName = classNames(`${preCls}-wrapper`, wrapperClassName, { [`${wrapperClassName}-rtl`]: direction.value === 'rtl', }); const mergedGroupClassName = classNames( `${preCls}-group-wrapper`, { [`${preCls}-group-wrapper-sm`]: mergeSize === 'small', [`${preCls}-group-wrapper-lg`]: mergeSize === 'large', [`${preCls}-group-wrapper-rtl`]: direction.value === 'rtl', }, className, ); element = ( {addonBeforeNode} {element} {addonAfterNode} ); } return cloneElement(element, { style }); }; }, }); export default Object.assign(InputNumber, { install: (app: App) => { app.component(InputNumber.name, InputNumber); return app; }, });