diff --git a/components/input/Password.tsx b/components/input/Password.tsx index 9556f1c8e7..d1a428a6b8 100644 --- a/components/input/Password.tsx +++ b/components/input/Password.tsx @@ -1,5 +1,6 @@ import classNames from '../_util/classNames'; import { getComponent, getOptionProps } from '../_util/props-util'; +import { cloneElement } from '../_util/vnode'; import Input from './Input'; import EyeOutlined from '@ant-design/icons-vue/EyeOutlined'; import EyeInvisibleOutlined from '@ant-design/icons-vue/EyeInvisibleOutlined'; @@ -23,6 +24,9 @@ export default defineComponent({ inputPrefixCls: PropTypes.string.def('ant-input'), action: PropTypes.string.def('click'), visibilityToggle: PropTypes.looseBool.def(true), + iconRender: PropTypes.func.def((visible: boolean) => + visible ? : , + ), }, setup() { return { @@ -55,6 +59,8 @@ export default defineComponent({ getIcon() { const { prefixCls, action } = this.$props; const iconTrigger = ActionMap[action] || ''; + const iconRender = this.$slots.iconRender || this.$props.iconRender; + const icon = iconRender(this.visible); const iconProps = { [iconTrigger]: this.onVisibleChange, onMousedown: (e: Event) => { @@ -70,11 +76,7 @@ export default defineComponent({ class: `${prefixCls}-icon`, key: 'passwordIcon', }; - return this.visible ? ( - - ) : ( - - ); + return cloneElement(icon, iconProps); }, }, render() { diff --git a/components/input/__tests__/index.test.js b/components/input/__tests__/index.test.js index 684411905c..944e86d748 100644 --- a/components/input/__tests__/index.test.js +++ b/components/input/__tests__/index.test.js @@ -3,6 +3,7 @@ import { asyncExpect } from '@/tests/utils'; import Input from '..'; // import Form from '../../form'; import focusTest from '../../../tests/shared/focusTest'; +import { WifiOutlined, SyncOutlined } from '@ant-design/icons-vue'; const { TextArea, Password } = Input; @@ -131,3 +132,35 @@ describe('Input.Search', () => { }, 100); }); }); + +describe('Input.Password', () => { + it('should support iconRender', async () => { + const wrapper = mount(Input.Password, { + props: { iconRender: visible => (visible ? : ) }, + sync: false, + }); + await asyncExpect(() => { + expect(wrapper.findAll('.anticon-wifi').length).toBe(1); + wrapper.find('.anticon-wifi').trigger('click'); + }, 100); + await asyncExpect(() => { + expect(wrapper.findAll('.anticon-sync').length).toBe(1); + }, 100); + }); + + it('should support slot iconRender', async () => { + const wrapper = mount(Input.Password, { + slots: { + iconRender: visible => (visible ? : ), + }, + sync: false, + }); + await asyncExpect(() => { + expect(wrapper.findAll('.anticon-wifi').length).toBe(1); + wrapper.find('.anticon-wifi').trigger('click'); + }, 100); + await asyncExpect(() => { + expect(wrapper.findAll('.anticon-sync').length).toBe(1); + }, 100); + }); +});