Skip to content

Commit 9c03115

Browse files
kovsutangjinzhou
andauthored
feat(input): add password visible feature (#6863)
* feat(input): modify visibilityToggle feature * test: update snapshot and update test cases * Update Password.tsx * Update Password.tsx * chore: update * chore: update demo and test --------- Co-authored-by: tangjinzhou <[email protected]>
1 parent 7f5b630 commit 9c03115

File tree

6 files changed

+103
-14
lines changed

6 files changed

+103
-14
lines changed

components/input/Password.tsx

+11-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
66
import EyeInvisibleOutlined from '@ant-design/icons-vue/EyeInvisibleOutlined';
77
import type { InputProps } from './inputProps';
88
import inputProps from './inputProps';
9-
import { computed, defineComponent, shallowRef } from 'vue';
9+
import type { PropType } from 'vue';
10+
import { computed, defineComponent, shallowRef, watchEffect } from 'vue';
1011
import useConfigInject from '../config-provider/hooks/useConfigInject';
1112
import omit from '../_util/omit';
1213

@@ -26,17 +27,25 @@ export default defineComponent({
2627
inputPrefixCls: String,
2728
action: { type: String, default: 'click' },
2829
visibilityToggle: { type: Boolean, default: true },
30+
visible: { type: Boolean, default: undefined },
31+
'onUpdate:visible': Function as PropType<(visible: boolean) => void>,
2932
iconRender: Function,
3033
},
31-
setup(props, { slots, attrs, expose }) {
34+
setup(props, { slots, attrs, expose, emit }) {
3235
const visible = shallowRef(false);
3336
const onVisibleChange = () => {
3437
const { disabled } = props;
3538
if (disabled) {
3639
return;
3740
}
3841
visible.value = !visible.value;
42+
emit('update:visible', visible.value);
3943
};
44+
watchEffect(() => {
45+
if (props.visible !== undefined) {
46+
visible.value = !!props.visible;
47+
}
48+
});
4049
const inputRef = shallowRef();
4150
const focus = () => {
4251
inputRef.value?.focus();

components/input/__tests__/__snapshots__/demo.test.js.snap

+28-5
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ exports[`renders ./components/input/demo/addon.vue correctly 1`] = `
3333
`;
3434
3535
exports[`renders ./components/input/demo/allow-clear.vue correctly 1`] = `
36-
<div><span class="ant-input-affix-wrapper"><!----><input placeholder="input with clear icon" type="text" class="ant-input"><span class="ant-input-suffix"><span class="ant-input-clear-icon-hidden ant-input-clear-icon" role="button" tabindex="-1"><span role="img" aria-label="close-circle" class="anticon anticon-close-circle"><svg focusable="false" class="" data-icon="close-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path></svg></span></span>
37-
<!----></span></span><br><br><span class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"><textarea placeholder="textarea with clear icon" class="ant-input"></textarea><span role="button" aria-label="close-circle" tabindex="-1" class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"><svg focusable="false" class="" data-icon="close-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"></path></svg></span></span>
36+
<div><span class="ant-input-affix-wrapper"><!----><input placeholder="input with clear icon" type="text" class="ant-input"><span class="ant-input-suffix"><span class="ant-input-clear-icon-hidden ant-input-clear-icon" role="button" tabindex="-1"><span role="img" aria-label="close-circle" class="anticon anticon-close-circle"><svg focusable="false" class="" data-icon="close-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" fill-rule="evenodd" viewBox="64 64 896 896"><path d="M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm127.98 274.82h-.04l-.08.06L512 466.75 384.14 338.88c-.04-.05-.06-.06-.08-.06a.12.12 0 00-.07 0c-.03 0-.05.01-.09.05l-45.02 45.02a.2.2 0 00-.05.09.12.12 0 000 .07v.02a.27.27 0 00.06.06L466.75 512 338.88 639.86c-.05.04-.06.06-.06.08a.12.12 0 000 .07c0 .03.01.05.05.09l45.02 45.02a.2.2 0 00.09.05.12.12 0 00.07 0c.02 0 .04-.01.08-.05L512 557.25l127.86 127.87c.04.04.06.05.08.05a.12.12 0 00.07 0c.03 0 .05-.01.09-.05l45.02-45.02a.2.2 0 00.05-.09.12.12 0 000-.07v-.02a.27.27 0 00-.05-.06L557.25 512l127.87-127.86c.04-.04.05-.06.05-.08a.12.12 0 000-.07c0-.03-.01-.05-.05-.09l-45.02-45.02a.2.2 0 00-.09-.05.12.12 0 00-.07 0z"></path></svg></span></span>
37+
<!----></span></span><br><br><span class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"><textarea placeholder="textarea with clear icon" class="ant-input"></textarea><span role="button" aria-label="close-circle" tabindex="-1" class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"><svg focusable="false" class="" data-icon="close-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" fill-rule="evenodd" viewBox="64 64 896 896"><path d="M512 64c247.4 0 448 200.6 448 448S759.4 960 512 960 64 759.4 64 512 264.6 64 512 64zm127.98 274.82h-.04l-.08.06L512 466.75 384.14 338.88c-.04-.05-.06-.06-.08-.06a.12.12 0 00-.07 0c-.03 0-.05.01-.09.05l-45.02 45.02a.2.2 0 00-.05.09.12.12 0 000 .07v.02a.27.27 0 00.06.06L466.75 512 338.88 639.86c-.05.04-.06.06-.06.08a.12.12 0 000 .07c0 .03.01.05.05.09l45.02 45.02a.2.2 0 00.09.05.12.12 0 00.07 0c.02 0 .04-.01.08-.05L512 557.25l127.86 127.87c.04.04.06.05.08.05a.12.12 0 00.07 0c.03 0 .05-.01.09-.05l45.02-45.02a.2.2 0 00.05-.09.12.12 0 000-.07v-.02a.27.27 0 00-.05-.06L557.25 512l127.87-127.86c.04-.04.05-.06.05-.08a.12.12 0 000-.07c0-.03-.01-.05-.05-.09l-45.02-45.02a.2.2 0 00-.09-.05.12.12 0 00-.07 0z"></path></svg></span></span>
3838
</div>
3939
`;
4040
@@ -124,14 +124,37 @@ exports[`renders ./components/input/demo/group.vue correctly 1`] = `
124124
`;
125125
126126
exports[`renders ./components/input/demo/password-input.vue correctly 1`] = `
127-
<span class="ant-input-affix-wrapper ant-input-password"><!----><input placeholder="input password" type="password" class="ant-input"><span class="ant-input-suffix"><!----><!----><span role="img" aria-label="eye-invisible" tabindex="-1" class="anticon anticon-eye-invisible ant-input-password-icon"><svg focusable="false" class="" data-icon="eye-invisible" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"></path><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"></path></svg></span>
128-
<!----></span></span>
127+
<div style="width: 100%;" class="ant-space ant-space-vertical">
128+
<div class="ant-space-item" style="margin-bottom: 16px;"><span class="ant-input-affix-wrapper ant-input-password"><!----><input placeholder="input password" type="password" class="ant-input"><span class="ant-input-suffix"><!----><!----><span role="img" aria-label="eye-invisible" tabindex="-1" class="anticon anticon-eye-invisible ant-input-password-icon"><svg focusable="false" class="" data-icon="eye-invisible" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"></path><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"></path></svg></span>
129+
<!----></span></span>
130+
</div>
131+
<!---->
132+
<div class="ant-space-item" style="margin-bottom: 16px;"><span class="ant-input-affix-wrapper ant-input-password"><!----><input placeholder="input password" type="password" class="ant-input"><span class="ant-input-suffix"><!----><!----><span role="img" aria-label="eye-invisible" tabindex="-1" class="anticon anticon-eye-invisible ant-input-password-icon"><svg focusable="false" class="" data-icon="eye-invisible" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"></path><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"></path></svg></span>
133+
<!----></span></span>
134+
</div>
135+
<!---->
136+
<div class="ant-space-item" style="margin-bottom: 16px;"><input placeholder="input password" type="password" class="ant-input"></div>
137+
<!---->
138+
<div class="ant-space-item">
139+
<div class="ant-space ant-space-horizontal ant-space-align-center">
140+
<div class="ant-space-item" style="margin-right: 8px;"><span class="ant-input-affix-wrapper ant-input-password"><!----><input placeholder="input password" type="text" visible="true" class="ant-input"><span class="ant-input-suffix"><!----><!----><span role="img" aria-label="eye" tabindex="-1" class="anticon anticon-eye ant-input-password-icon"><svg focusable="false" class="" data-icon="eye" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3 7.7-16.2 7.7-35 0-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766zm-4-430c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z"></path></svg></span>
141+
<!----></span></span>
142+
</div>
143+
<!---->
144+
<div class="ant-space-item"><button class="ant-btn ant-btn-default" type="button">
145+
<!----><span>Hide</span>
146+
</button></div>
147+
<!---->
148+
</div>
149+
</div>
150+
<!---->
151+
</div>
129152
`;
130153
131154
exports[`renders ./components/input/demo/presuffix.vue correctly 1`] = `
132155
<div class="components-input-demo-presuffix"><span class="ant-input-affix-wrapper"><span class="ant-input-prefix"><span role="img" aria-label="user" type="user" class="anticon anticon-user"><svg focusable="false" class="" data-icon="user" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M858.5 763.6a374 374 0 00-80.6-119.5 375.63 375.63 0 00-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 00-80.6 119.5A371.7 371.7 0 00136 901.8a8 8 0 008 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 008-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"></path></svg></span></span><input placeholder="Basic usage" type="text" class="ant-input"><span class="ant-input-suffix"><!----><!----><span role="img" aria-label="info-circle" style="color: rgba(0, 0, 0, 0.45);" tabindex="-1" class="anticon anticon-info-circle"><svg focusable="false" class="" data-icon="info-circle" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"></path><path d="M464 336a48 48 0 1096 0 48 48 0 10-96 0zm72 112h-48c-4.4 0-8 3.6-8 8v272c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V456c0-4.4-3.6-8-8-8z"></path></svg></span>
133156
<!---->
134-
<!----></span></span><br><br><span class="ant-input-affix-wrapper"><!----><input type="text" class="ant-input"><span class="ant-input-suffix"><!----><!---->RMB<!----></span></span>
157+
<!----></span></span><br><br><span class="ant-input-affix-wrapper"><span class="ant-input-prefix">¥</span><input type="text" class="ant-input"><span class="ant-input-suffix"><!----><!---->RMB<!----></span></span>
135158
</div>
136159
`;
137160

components/input/__tests__/index.test.js

+26
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,30 @@ describe('Input.Password', () => {
163163
expect(wrapper.findAll('.anticon-sync').length).toBe(1);
164164
}, 100);
165165
});
166+
167+
it('should support visibilityToggle(boolean)', async () => {
168+
const wrapper = mount(Input.Password, { props: { visibilityToggle: false }, sync: false });
169+
await asyncExpect(() => {
170+
expect(wrapper.findAll('.anticon-eye').length).toBe(0);
171+
}, 100);
172+
});
173+
174+
it('should support visible', async () => {
175+
const cbMock = jest.fn();
176+
const wrapper = mount({
177+
render() {
178+
return <Password {...{ 'onUpdate:visible': cbMock }} visible="false"></Password>;
179+
},
180+
});
181+
182+
await asyncExpect(() => {
183+
expect(wrapper.findAll('.anticon-eye').length).toBe(1);
184+
}, 100);
185+
186+
await asyncExpect(() => {
187+
wrapper.find('.anticon-eye').trigger('click');
188+
}, 100);
189+
190+
expect(cbMock).toHaveBeenCalledWith(false);
191+
});
166192
});

components/input/demo/password-input.vue

+28-1
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,36 @@ Input type of password.
1616

1717
</docs>
1818
<template>
19-
<a-input-password v-model:value="value" placeholder="input password" />
19+
<a-space direction="vertical" size="middle" style="width: 100%">
20+
<a-input-password v-model:value="value" placeholder="input password" />
21+
<a-input-password v-model:value="value2" placeholder="input password">
22+
<template #iconRender="visible">
23+
<EyeTwoTone v-if="visible"></EyeTwoTone>
24+
<EyeInvisibleOutlined v-else></EyeInvisibleOutlined>
25+
</template>
26+
</a-input-password>
27+
<a-input-password
28+
v-model:value="value3"
29+
placeholder="input password"
30+
:visibility-toggle="false"
31+
/>
32+
<a-space>
33+
<a-input-password
34+
v-model:value="value4"
35+
v-model:visible="visible"
36+
placeholder="input password"
37+
/>
38+
<a-button @click="visible = !visible">{{ visible ? 'Hide' : 'Show' }}</a-button>
39+
</a-space>
40+
</a-space>
2041
</template>
2142
<script lang="ts" setup>
2243
import { ref } from 'vue';
44+
import { EyeTwoTone, EyeInvisibleOutlined } from '@ant-design/icons-vue';
2345
const value = ref<string>('');
46+
const value2 = ref<string>('');
47+
const value3 = ref<string>('');
48+
const value4 = ref<string>('');
49+
50+
const visible = ref<boolean>(true);
2451
</script>

components/input/index.en-US.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ Supports all props of `Input`.
9494

9595
#### Input.Password (Added in 1.14.0)
9696

97-
| Property | Description | Type | Default |
98-
| ---------------- | -------------------------- | ------- | ------- |
99-
| visibilityToggle | Whether show toggle button | boolean | true |
97+
| Property | Description | Type | Default |
98+
| ---------------- | ------------------------------------------------------ | ------- | ------- |
99+
| visible(v-model) | password visibility | boolean | false |
100+
| iconRender | Custom toggle button | slot | - |
101+
| visibilityToggle | Whether show toggle button or control password visible | boolean | true |

components/input/index.zh-CN.md

+5-3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sBqqTatJ-AkAAA
9595

9696
#### Input.Password (1.14.0 中新增)
9797

98-
| 参数 | 说明 | 类型 | 默认值 |
99-
| ---------------- | ---------------- | ------- | ------ |
100-
| visibilityToggle | 是否显示切换按钮 | boolean | true |
98+
| 参数 | 说明 | 类型 | 默认值 |
99+
| ---------------- | -------------------------------- | ------- | ------ |
100+
| visible(v-model) | 密码是否可见 | boolean | false |
101+
| iconRender | 自定义切换按钮 | slot | - |
102+
| visibilityToggle | 是否显示切换按钮或者控制密码显隐 | boolean | true |

0 commit comments

Comments
 (0)