Skip to content

Commit

Permalink
feat(input): add password visible feature (#6863)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
kovsu and tangjinzhou authored Aug 18, 2023
1 parent 7f5b630 commit 9c03115
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 14 deletions.
13 changes: 11 additions & 2 deletions components/input/Password.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import EyeOutlined from '@ant-design/icons-vue/EyeOutlined';
import EyeInvisibleOutlined from '@ant-design/icons-vue/EyeInvisibleOutlined';
import type { InputProps } from './inputProps';
import inputProps from './inputProps';
import { computed, defineComponent, shallowRef } from 'vue';
import type { PropType } from 'vue';
import { computed, defineComponent, shallowRef, watchEffect } from 'vue';
import useConfigInject from '../config-provider/hooks/useConfigInject';
import omit from '../_util/omit';

Expand All @@ -26,17 +27,25 @@ export default defineComponent({
inputPrefixCls: String,
action: { type: String, default: 'click' },
visibilityToggle: { type: Boolean, default: true },
visible: { type: Boolean, default: undefined },
'onUpdate:visible': Function as PropType<(visible: boolean) => void>,
iconRender: Function,
},
setup(props, { slots, attrs, expose }) {
setup(props, { slots, attrs, expose, emit }) {
const visible = shallowRef(false);
const onVisibleChange = () => {
const { disabled } = props;
if (disabled) {
return;
}
visible.value = !visible.value;
emit('update:visible', visible.value);
};
watchEffect(() => {
if (props.visible !== undefined) {
visible.value = !!props.visible;
}
});
const inputRef = shallowRef();
const focus = () => {
inputRef.value?.focus();
Expand Down
33 changes: 28 additions & 5 deletions components/input/__tests__/__snapshots__/demo.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ exports[`renders ./components/input/demo/addon.vue correctly 1`] = `
`;
exports[`renders ./components/input/demo/allow-clear.vue correctly 1`] = `
<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>
<!----></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>
<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>
<!----></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>
</div>
`;
Expand Down Expand Up @@ -124,14 +124,37 @@ exports[`renders ./components/input/demo/group.vue correctly 1`] = `
`;
exports[`renders ./components/input/demo/password-input.vue correctly 1`] = `
<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>
<!----></span></span>
<div style="width: 100%;" class="ant-space ant-space-vertical">
<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>
<!----></span></span>
</div>
<!---->
<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>
<!----></span></span>
</div>
<!---->
<div class="ant-space-item" style="margin-bottom: 16px;"><input placeholder="input password" type="password" class="ant-input"></div>
<!---->
<div class="ant-space-item">
<div class="ant-space ant-space-horizontal ant-space-align-center">
<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>
<!----></span></span>
</div>
<!---->
<div class="ant-space-item"><button class="ant-btn ant-btn-default" type="button">
<!----><span>Hide</span>
</button></div>
<!---->
</div>
</div>
<!---->
</div>
`;
exports[`renders ./components/input/demo/presuffix.vue correctly 1`] = `
<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>
<!---->
<!----></span></span><br><br><span class="ant-input-affix-wrapper"><!----><input type="text" class="ant-input"><span class="ant-input-suffix"><!----><!---->RMB<!----></span></span>
<!----></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>
</div>
`;
Expand Down
26 changes: 26 additions & 0 deletions components/input/__tests__/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,30 @@ describe('Input.Password', () => {
expect(wrapper.findAll('.anticon-sync').length).toBe(1);
}, 100);
});

it('should support visibilityToggle(boolean)', async () => {
const wrapper = mount(Input.Password, { props: { visibilityToggle: false }, sync: false });
await asyncExpect(() => {
expect(wrapper.findAll('.anticon-eye').length).toBe(0);
}, 100);
});

it('should support visible', async () => {
const cbMock = jest.fn();
const wrapper = mount({
render() {
return <Password {...{ 'onUpdate:visible': cbMock }} visible="false"></Password>;
},
});

await asyncExpect(() => {
expect(wrapper.findAll('.anticon-eye').length).toBe(1);
}, 100);

await asyncExpect(() => {
wrapper.find('.anticon-eye').trigger('click');
}, 100);

expect(cbMock).toHaveBeenCalledWith(false);
});
});
29 changes: 28 additions & 1 deletion components/input/demo/password-input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,36 @@ Input type of password.

</docs>
<template>
<a-input-password v-model:value="value" placeholder="input password" />
<a-space direction="vertical" size="middle" style="width: 100%">
<a-input-password v-model:value="value" placeholder="input password" />
<a-input-password v-model:value="value2" placeholder="input password">
<template #iconRender="visible">
<EyeTwoTone v-if="visible"></EyeTwoTone>
<EyeInvisibleOutlined v-else></EyeInvisibleOutlined>
</template>
</a-input-password>
<a-input-password
v-model:value="value3"
placeholder="input password"
:visibility-toggle="false"
/>
<a-space>
<a-input-password
v-model:value="value4"
v-model:visible="visible"
placeholder="input password"
/>
<a-button @click="visible = !visible">{{ visible ? 'Hide' : 'Show' }}</a-button>
</a-space>
</a-space>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { EyeTwoTone, EyeInvisibleOutlined } from '@ant-design/icons-vue';
const value = ref<string>('');
const value2 = ref<string>('');
const value3 = ref<string>('');
const value4 = ref<string>('');
const visible = ref<boolean>(true);
</script>
8 changes: 5 additions & 3 deletions components/input/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ Supports all props of `Input`.

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

| Property | Description | Type | Default |
| ---------------- | -------------------------- | ------- | ------- |
| visibilityToggle | Whether show toggle button | boolean | true |
| Property | Description | Type | Default |
| ---------------- | ------------------------------------------------------ | ------- | ------- |
| visible(v-model) | password visibility | boolean | false |
| iconRender | Custom toggle button | slot | - |
| visibilityToggle | Whether show toggle button or control password visible | boolean | true |
8 changes: 5 additions & 3 deletions components/input/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*sBqqTatJ-AkAAA

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

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

0 comments on commit 9c03115

Please sign in to comment.