import classNames from '../_util/classNames'; import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled'; import { getInputClassName } from './Input'; import PropTypes from '../_util/vue-types'; import { cloneElement } from '../_util/vnode'; import { getComponent } from '../_util/props-util'; import type { VNode } from 'vue'; import { defineComponent } from 'vue'; import { tuple } from '../_util/type'; export function hasPrefixSuffix(instance: any) { return !!( getComponent(instance, 'prefix') || getComponent(instance, 'suffix') || instance.$props.allowClear ); } const ClearableInputType = ['text', 'input']; const ClearableLabeledInput = defineComponent({ name: 'ClearableLabeledInput', inheritAttrs: false, props: { prefixCls: PropTypes.string, inputType: PropTypes.oneOf(tuple('text', 'input')), value: PropTypes.any, defaultValue: PropTypes.any, allowClear: PropTypes.looseBool, element: PropTypes.VNodeChild, handleReset: PropTypes.func, disabled: PropTypes.looseBool, size: PropTypes.oneOf(tuple('small', 'large', 'default')), suffix: PropTypes.VNodeChild, prefix: PropTypes.VNodeChild, addonBefore: PropTypes.VNodeChild, addonAfter: PropTypes.VNodeChild, readonly: PropTypes.looseBool, isFocused: PropTypes.looseBool, }, methods: { renderClearIcon(prefixCls: string) { const { allowClear, value, disabled, readonly, inputType, handleReset } = this.$props; if (!allowClear) { return null; } const showClearIcon = !disabled && !readonly && value !== undefined && value !== null && value !== ''; const className = inputType === ClearableInputType[0] ? `${prefixCls}-textarea-clear-icon` : `${prefixCls}-clear-icon`; return ( ); }, renderSuffix(prefixCls: string) { const { suffix, allowClear } = this.$props; if (suffix || allowClear) { return ( {this.renderClearIcon(prefixCls)} {suffix} ); } return null; }, renderLabeledIcon(prefixCls: string, element: VNode): VNode { const props = this.$props; const { style } = this.$attrs; const suffix = this.renderSuffix(prefixCls); if (!hasPrefixSuffix(this)) { return cloneElement(element, { value: props.value, }); } const prefix = props.prefix ? ( {props.prefix} ) : null; const affixWrapperCls = classNames(this.$attrs?.class, `${prefixCls}-affix-wrapper`, { [`${prefixCls}-affix-wrapper-focused`]: props.isFocused, [`${prefixCls}-affix-wrapper-disabled`]: props.disabled, [`${prefixCls}-affix-wrapper-sm`]: props.size === 'small', [`${prefixCls}-affix-wrapper-lg`]: props.size === 'large', [`${prefixCls}-affix-wrapper-input-with-clear-btn`]: props.suffix && props.allowClear && this.$props.value, }); return ( {prefix} {cloneElement(element, { style: null, value: props.value, class: getInputClassName(prefixCls, props.size, props.disabled), })} {suffix} ) as VNode; }, renderInputWithLabel(prefixCls: string, labeledElement: VNode) { const { addonBefore, addonAfter, size } = this.$props; const { style, class: className } = this.$attrs; // Not wrap when there is not addons if (!addonBefore && !addonAfter) { return labeledElement; } const wrapperClassName = `${prefixCls}-group`; const addonClassName = `${wrapperClassName}-addon`; const addonBeforeNode = addonBefore ? ( {addonBefore} ) : null; const addonAfterNode = addonAfter ? {addonAfter} : null; const mergedWrapperClassName = classNames(`${prefixCls}-wrapper`, { [wrapperClassName]: addonBefore || addonAfter, }); const mergedGroupClassName = classNames(className, `${prefixCls}-group-wrapper`, { [`${prefixCls}-group-wrapper-sm`]: size === 'small', [`${prefixCls}-group-wrapper-lg`]: size === 'large', }); // Need another wrapper for changing display:table to display:inline-block // and put style prop in wrapper return ( {addonBeforeNode} {cloneElement(labeledElement, { style: null })} {addonAfterNode} ); }, renderTextAreaWithClearIcon(prefixCls: string, element: VNode) { const { value, allowClear } = this.$props; const { style, class: className } = this.$attrs; if (!allowClear) { return cloneElement(element, { value }); } const affixWrapperCls = classNames( className, `${prefixCls}-affix-wrapper`, `${prefixCls}-affix-wrapper-textarea-with-clear-btn`, ); return ( {cloneElement(element, { style: null, value, })} {this.renderClearIcon(prefixCls)} ); }, renderClearableLabeledInput() { const { prefixCls, inputType, element } = this.$props as any; if (inputType === ClearableInputType[0]) { return this.renderTextAreaWithClearIcon(prefixCls, element); } return this.renderInputWithLabel(prefixCls, this.renderLabeledIcon(prefixCls, element)); }, }, render() { return this.renderClearableLabeledInput(); }, }); export default ClearableLabeledInput;