Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: made a new password input component #108

Merged
merged 10 commits into from
Nov 1, 2023
Merged
16 changes: 8 additions & 8 deletions src/components/PasswordInput/PasswordInput.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@
$block: '.#{variables.$ns}password-input';

#{$block} {
&__additional-right-content {
display: flex;
&::-ms-reveal,
&::-ms-clear {
display: none;
}

&__button {
--yc-button-background-color-hover: transparent;
&__additional-right-content {
display: flex;
align-items: center;
}

&__input {
::-ms-reveal {
display: none;
}
&__copy-button {
margin-right: 4px;
}
}
83 changes: 47 additions & 36 deletions src/components/PasswordInput/PasswordInput.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import React from 'react';

import {Copy, CopyCheck, Eye, EyeSlash} from '@gravity-ui/icons';
import {
Button,
CopyToClipboard,
CopyToClipboardStatus,
Icon,
TextInput,
TextInputProps,
} from '@gravity-ui/uikit';
import {Eye, EyeSlash} from '@gravity-ui/icons';
import {Button, ClipboardButton, TextInput, TextInputProps, Tooltip} from '@gravity-ui/uikit';

import {block} from '../utils/cn';

import i18n from './i18n';

import './PasswordInput.scss';

const b = block('password-input');
Expand All @@ -20,18 +15,27 @@ export type PasswordInputProps = Required<Pick<TextInputProps, 'onUpdate' | 'val
Omit<TextInputProps, 'type'> & {
/** Show copy button */
showCopyButton?: boolean;
/** Show visibility button */
showVisibilityButton?: boolean;
/** Show reveal button */
showRevealButton?: boolean;
/** Disable tooltip. Tooltip won't be shown */
hasTooltip?: boolean;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would pick separate names here, hasCopyTooltip and hasRevealTooltip

};

export const PasswordInput: React.FC<PasswordInputProps> = (props) => {
const {autoComplete, value, showCopyButton, rightContent, showVisibilityButton, className} =
props;
const {
autoComplete,
value,
showCopyButton,
rightContent,
showRevealButton,
size = 'm',
hasTooltip = true,
} = props;

const [hideValue, setHideValue] = React.useState(true);

const additionalRightContent = React.useMemo(() => {
if (!showVisibilityButton && !showCopyButton) {
if (!showRevealButton && !showCopyButton) {
return <React.Fragment>{rightContent}</React.Fragment>;
}

Expand All @@ -43,40 +47,47 @@ export const PasswordInput: React.FC<PasswordInputProps> = (props) => {
<div className={b('additional-right-content')}>
{rightContent}
{value && showCopyButton ? (
<CopyToClipboard text={String(value)} timeout={500}>
{(state) => (
<Button view="flat-secondary" className={b('button')} size="s">
<Icon
size={14}
data={
state === CopyToClipboardStatus.Pending ? Copy : CopyCheck
}
/>
</Button>
)}
</CopyToClipboard>
<ClipboardButton
text={value}
hasTooltip={hasTooltip}
size={16}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should map input size to button size

className={b('copy-button')}
/>
) : null}
{showVisibilityButton ? (
<Button
view="flat-secondary"
onClick={onClick}
className={b('button')}
size="s"
{showRevealButton ? (
<Tooltip
disabled={!hasTooltip}
content={
hideValue ? i18n('label_show-password') : i18n('label_hide-password')
}
>
<Icon data={hideValue ? Eye : EyeSlash} size={14} />
</Button>
<Button
view="flat-secondary"
onClick={onClick}
size={size}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextInput size !== Button size, take a look at clear button, maybe reuse this logic here as well

extraProps={{
'aria-label': hideValue
? i18n('label_show-password')
: i18n('label_hide-password'),
}}
>
<Button.Icon>{hideValue ? <Eye /> : <EyeSlash />}</Button.Icon>
</Button>
</Tooltip>
) : null}
</div>
);
}, [rightContent, value, showCopyButton, showVisibilityButton, hideValue]);
}, [showRevealButton, showCopyButton, rightContent, value, hasTooltip, hideValue, size]);

return (
<TextInput
{...props}
type={hideValue ? 'password' : 'text'}
rightContent={additionalRightContent}
autoComplete={autoComplete ? autoComplete : 'new-password'}
className={b('input', className)}
controlProps={{
className: b(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it's an opposite, you're passing root className (b()) to the control node

}}
/>
);
};
9 changes: 5 additions & 4 deletions src/components/PasswordInput/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ Same as [TextInput component](https://github.com/gravity-ui/uikit/blob/main/src/
- `onUpdate` is required property;
- `type` is omitted;

| Property | Type | Required | Default | Description |
| :------------------- | :-------- | :------- | :------ | :--------------------- |
| showCopyButton | `boolean` | | | Show copy button |
| showVisibilityButton | `boolean` | | | Show visibility button |
| Property | Type | Required | Default | Description |
| :--------------- | :-------- | :------- | :------ | :-------------------------------------- |
| showCopyButton | `boolean` | | | Show copy button |
| showRevealButton | `boolean` | | | Show reveal button |
| hasTooltip | `boolean` | | `true` | Disable tooltip. Tooltip won't be shown |

#### Usage example

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const DefaultTemplate: StoryFn<React.ComponentProps<typeof PasswordInput>> = ()
return (
<PasswordInput
showCopyButton={true}
showVisibilityButton={true}
showRevealButton={true}
onUpdate={setValue}
value={value}
/>
Expand Down
4 changes: 4 additions & 0 deletions src/components/PasswordInput/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label_show-password": "Show password",
"label_hide-password": "Hide password"
}
8 changes: 8 additions & 0 deletions src/components/PasswordInput/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {registerKeyset} from '../../utils/registerKeyset';

import en from './en.json';
import ru from './ru.json';

const COMPONENT = 'PasswordInput';

export default registerKeyset({en, ru}, COMPONENT);
4 changes: 4 additions & 0 deletions src/components/PasswordInput/i18n/ru.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label_show-password": "Показать пароль",
"label_hide-password": "Скрыть пароль"
}
Loading