-
Notifications
You must be signed in to change notification settings - Fork 98
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(PaswordInput): added new input Password Input
- Loading branch information
1 parent
d8ba39d
commit 44ef301
Showing
22 changed files
with
321 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
@use '../../variables'; | ||
|
||
$block: '.#{variables.$ns}password-input'; | ||
|
||
#{$block} { | ||
&__input-control { | ||
&::-ms-reveal, | ||
&::-ms-clear { | ||
display: none; | ||
} | ||
} | ||
|
||
&__additional-end-content { | ||
display: flex; | ||
align-items: center; | ||
} | ||
|
||
&__copy-button { | ||
margin-inline-end: 4px; | ||
} | ||
} |
118 changes: 118 additions & 0 deletions
118
src/components/controls/PasswordInput/PasswordInput.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import React from 'react'; | ||
|
||
import {Eye, EyeSlash} from '@gravity-ui/icons'; | ||
|
||
import {ActionTooltip} from '../../ActionTooltip'; | ||
import {Button} from '../../Button'; | ||
import {ClipboardButton} from '../../ClipboardButton'; | ||
import {Icon} from '../../Icon'; | ||
import {block} from '../../utils/cn'; | ||
import {TextInput} from '../TextInput'; | ||
import type {TextInputProps} from '../TextInput'; | ||
|
||
import {i18n} from './i18n'; | ||
import {getActionButtonSizeAndIconSize} from './utils'; | ||
|
||
import './PasswordInput.scss'; | ||
|
||
const b = block('password-input'); | ||
|
||
export type PasswordInputProps = Required<Pick<TextInputProps, 'onUpdate' | 'value'>> & | ||
Omit<TextInputProps, 'type'> & { | ||
/** Show copy button */ | ||
showCopyButton?: boolean; | ||
/** Show reveal button */ | ||
showRevealButton?: boolean; | ||
/** Disable the tooltip for the copy button. The tooltip will not be displayed */ | ||
hasCopyTooltip?: boolean; | ||
/** Disable the tooltip for the reveal button. The tooltip will not be displayed */ | ||
hasRevealTooltip?: boolean; | ||
}; | ||
|
||
export const PasswordInput = (props: PasswordInputProps) => { | ||
const { | ||
autoComplete, | ||
value, | ||
showCopyButton, | ||
rightContent, | ||
endContent, | ||
showRevealButton, | ||
size = 'm', | ||
hasCopyTooltip = true, | ||
hasRevealTooltip = true, | ||
controlProps, | ||
} = props; | ||
|
||
const [hideValue, setHideValue] = React.useState(true); | ||
|
||
const additionalEndContent = React.useMemo(() => { | ||
if (!showRevealButton && !showCopyButton) { | ||
return <React.Fragment>{endContent || rightContent}</React.Fragment>; | ||
} | ||
|
||
const onClick = () => { | ||
setHideValue((hideValue) => !hideValue); | ||
}; | ||
|
||
const {actionButtonSize, iconSize} = getActionButtonSizeAndIconSize(size); | ||
|
||
return ( | ||
<div className={b('additional-end-content')}> | ||
{endContent || rightContent} | ||
{value && showCopyButton ? ( | ||
<ClipboardButton | ||
view="flat-secondary" | ||
text={value} | ||
hasTooltip={hasCopyTooltip} | ||
size={actionButtonSize} | ||
className={b('copy-button')} | ||
/> | ||
) : null} | ||
{showRevealButton ? ( | ||
<ActionTooltip | ||
disabled={!hasRevealTooltip} | ||
title={ | ||
hideValue ? i18n('label_show-password') : i18n('label_hide-password') | ||
} | ||
> | ||
<Button | ||
view="flat-secondary" | ||
onClick={onClick} | ||
size={actionButtonSize} | ||
extraProps={{ | ||
'aria-label': hideValue | ||
? i18n('label_show-password') | ||
: i18n('label_hide-password'), | ||
}} | ||
> | ||
<Icon data={hideValue ? Eye : EyeSlash} size={iconSize} /> | ||
</Button> | ||
</ActionTooltip> | ||
) : null} | ||
</div> | ||
); | ||
}, [ | ||
showRevealButton, | ||
showCopyButton, | ||
endContent, | ||
rightContent, | ||
value, | ||
hasRevealTooltip, | ||
hasCopyTooltip, | ||
hideValue, | ||
size, | ||
]); | ||
|
||
return ( | ||
<TextInput | ||
{...props} | ||
type={hideValue ? 'password' : 'text'} | ||
endContent={additionalEndContent} | ||
autoComplete={autoComplete ? autoComplete : 'new-password'} | ||
controlProps={{ | ||
...controlProps, | ||
className: b('input-control', controlProps?.className), | ||
}} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
## Password Input | ||
|
||
```tsx | ||
import {PasswordInput} from '@gravity-ui/uikit'; | ||
``` | ||
|
||
Password Input display component | ||
|
||
### PropTypes | ||
|
||
Same as [TextInput component](https://github.com/gravity-ui/uikit/blob/main/src/components/controls/TextInput/README.md), with some exceptions: | ||
|
||
- `value` is required property; | ||
- `onUpdate` is required property; | ||
- `type` is omitted; | ||
|
||
| Property | Type | Required | Default | Description | | ||
| :--------------- | :-------- | :------- | :------ | :--------------------------------------------------------------------------- | | ||
| showCopyButton | `boolean` | | | Show copy button | | ||
| showRevealButton | `boolean` | | | Show reveal button | | ||
| hasCopyTooltip | `boolean` | | `true` | Disable the tooltip for the copy button. The tooltip will not be displayed | | ||
| hasRevealTooltip | `boolean` | | `true` | Disable the tooltip for the reveal button. The tooltip will not be displayed | | ||
|
||
#### Usage example | ||
|
||
```jsx harmony | ||
function MyComponent() { | ||
const [value, setValue] = React.useState(''); | ||
|
||
return ( | ||
<PasswordInput | ||
showCopyButton={true} | ||
showRevealButton={true} | ||
onUpdate={setValue} | ||
value={value} | ||
/> | ||
); | ||
} | ||
``` |
Binary file added
BIN
+2.93 KB
...tsx-snapshots/PasswordInputStories-render-story-Default-dark-chromium-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+2.69 KB
...t.tsx-snapshots/PasswordInputStories-render-story-Default-dark-webkit-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+2.71 KB
...sx-snapshots/PasswordInputStories-render-story-Default-light-chromium-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+2.48 KB
....tsx-snapshots/PasswordInputStories-render-story-Default-light-webkit-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+8.76 KB
...sswordInputStories-render-story-WithGenerateRandomValue-dark-chromium-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+6.86 KB
...PasswordInputStories-render-story-WithGenerateRandomValue-dark-webkit-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+8.43 KB
...swordInputStories-render-story-WithGenerateRandomValue-light-chromium-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+6.39 KB
...asswordInputStories-render-story-WithGenerateRandomValue-light-webkit-linux.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import {Meta, Markdown} from '@storybook/addon-docs'; | ||
import * as Stories from './PasswordInput.stories'; | ||
import Readme from '../README.md?raw'; | ||
|
||
<Meta of={Stories} /> | ||
|
||
<Markdown>{Readme}</Markdown> |
61 changes: 61 additions & 0 deletions
61
src/components/controls/PasswordInput/__stories__/PasswordInput.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import React from 'react'; | ||
|
||
import type {Meta, StoryFn} from '@storybook/react'; | ||
|
||
import {Button} from '../../../Button'; | ||
import {cn} from '../../../utils/cn'; | ||
import type {PasswordInputProps} from '../PasswordInput'; | ||
import {PasswordInput} from '../PasswordInput'; | ||
|
||
import './PasswordInputStories.scss'; | ||
|
||
const b = cn('password-input-stories'); | ||
|
||
export default { | ||
title: 'Components/Inputs/PasswordInput', | ||
component: PasswordInput, | ||
args: { | ||
showCopyButton: true, | ||
showRevealButton: true, | ||
controlProps: { | ||
'aria-label': 'Password', | ||
}, | ||
}, | ||
} as Meta<typeof PasswordInput>; | ||
|
||
const DefaultTemplate: StoryFn<PasswordInputProps> = (args) => { | ||
const [value, setValue] = React.useState(''); | ||
|
||
return <PasswordInput {...args} onUpdate={setValue} value={value} />; | ||
}; | ||
|
||
export const Default = DefaultTemplate.bind({}); | ||
|
||
const WithGenerateRandomValueTemplate: StoryFn<PasswordInputProps> = (args) => { | ||
const [value, setValue] = React.useState(''); | ||
|
||
const generateRandomValue = React.useCallback(() => { | ||
let randomValue = ''; | ||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; | ||
const charactersLength = characters.length; | ||
let counter = 0; | ||
|
||
while (counter < charactersLength) { | ||
randomValue += characters.charAt(Math.floor(Math.random() * charactersLength)); | ||
counter += 1; | ||
} | ||
|
||
setValue(randomValue); | ||
}, []); | ||
|
||
return ( | ||
<div className={b()}> | ||
<PasswordInput {...args} onUpdate={setValue} value={value} /> | ||
<Button onClick={generateRandomValue} className={b('button-generate-random-value')}> | ||
Generate random value | ||
</Button> | ||
</div> | ||
); | ||
}; | ||
|
||
export const WithGenerateRandomValue = WithGenerateRandomValueTemplate.bind({}); |
7 changes: 7 additions & 0 deletions
7
src/components/controls/PasswordInput/__stories__/PasswordInputStories.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.password-input-stories { | ||
display: flex; | ||
|
||
&__button-generate-random-value { | ||
margin-inline-start: 8px; | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/components/controls/PasswordInput/__tests__/PasswordInput.visual.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React from 'react'; | ||
|
||
import {test} from '~playwright/core'; | ||
|
||
import {PasswordInputStories} from './helpersPlaywright'; | ||
|
||
test.describe('PasswordInputStories', () => { | ||
test('render story: <Default>', async ({mount, expectScreenshot}) => { | ||
await mount(<PasswordInputStories.Default />); | ||
|
||
await expectScreenshot(); | ||
}); | ||
|
||
test('render story: <WithGenerateRandomValue>', async ({mount, expectScreenshot}) => { | ||
await mount(<PasswordInputStories.WithGenerateRandomValue />); | ||
|
||
await expectScreenshot(); | ||
}); | ||
}); |
5 changes: 5 additions & 0 deletions
5
src/components/controls/PasswordInput/__tests__/helpersPlaywright.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import {composeStories} from '@storybook/react'; | ||
|
||
import * as DefaultPasswordInputStories from '../__stories__/PasswordInput.stories'; | ||
|
||
export const PasswordInputStories = composeStories(DefaultPasswordInputStories); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"label_show-password": "Show password", | ||
"label_hide-password": "Hide password" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import {addComponentKeysets} from '../../../utils/addComponentKeysets'; | ||
|
||
import en from './en.json'; | ||
import ru from './ru.json'; | ||
|
||
const COMPONENT = 'passwordInput'; | ||
|
||
export const i18n = addComponentKeysets({en, ru}, COMPONENT); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"label_show-password": "Показать пароль", | ||
"label_hide-password": "Скрыть пароль" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './PasswordInput'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import type {ButtonSize} from '../../Button'; | ||
import type {InputControlSize} from '../types'; | ||
|
||
export const getActionButtonSizeAndIconSize = ( | ||
textInputSize: InputControlSize, | ||
): {actionButtonSize: ButtonSize; iconSize: number} => { | ||
let actionButtonSize: ButtonSize = 's'; | ||
let iconSize = 16; | ||
|
||
switch (textInputSize) { | ||
case 's': { | ||
actionButtonSize = 'xs'; | ||
iconSize = 12; | ||
break; | ||
} | ||
case 'l': { | ||
actionButtonSize = 'm'; | ||
break; | ||
} | ||
case 'xl': { | ||
actionButtonSize = 'l'; | ||
} | ||
} | ||
|
||
return {actionButtonSize, iconSize}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './TextArea'; | ||
export * from './TextInput'; | ||
export * from './PasswordInput'; | ||
export type {InputControlPin, InputControlSize, InputControlState, InputControlView} from './types'; |