diff --git a/native/account/log-in-panel.react.js b/native/account/log-in-panel.react.js --- a/native/account/log-in-panel.react.js +++ b/native/account/log-in-panel.react.js @@ -37,6 +37,7 @@ setNativeCredentials, } from './native-credentials'; import { PanelButton, Panel } from './panel-components.react'; +import { PasswordInput } from './password-input.react'; export type LogInState = { +usernameInputText: ?string, @@ -59,7 +60,7 @@ }; class LogInPanel extends React.PureComponent { usernameInput: ?TextInput; - passwordInput: ?TextInput; + passwordInput: ?PasswordInput; componentDidMount() { this.attemptToFetchCredentials(); @@ -132,14 +133,14 @@ color="#555" style={styles.icon} /> - void = passwordInput => { + passwordInputRef: (passwordInput: ?PasswordInput) => void = passwordInput => { this.passwordInput = passwordInput; }; diff --git a/native/account/password-input.react.js b/native/account/password-input.react.js new file mode 100644 --- /dev/null +++ b/native/account/password-input.react.js @@ -0,0 +1,75 @@ +// @flow + +import * as React from 'react'; +import { TextInput as BaseTextInput, View, StyleSheet } from 'react-native'; + +import Button from '../components/button.react'; +import SWMansionIcon from '../components/swmansion-icon.react'; +import { TextInput } from './modal-components.react'; + +type Props = React.ElementConfig; + +type State = { + +secureTextEntry: boolean, +}; + +class PasswordInput extends React.PureComponent { + wrappedTextInput: ?TextInput; + constructor(props: Props) { + super(props); + this.state = { secureTextEntry: true }; + } + + onToggleShowPassword: () => void = () => { + this.setState(state => ({ + secureTextEntry: !state.secureTextEntry, + })); + }; + + render(): React.Node { + const { style, ...rest } = this.props; + return ( + + + + + ); + } + + wrappedTextInputRef: (wrappedTextInput: ?TextInput) => void = ( + wrappedTextInput: ?TextInput, + ) => { + this.wrappedTextInput = wrappedTextInput; + }; + + focus() { + this.wrappedTextInput?.focus(); + } +} + +const styles = StyleSheet.create({ + button: { + borderRadius: 21, + bottom: 0, + margin: 2, + padding: 8, + position: 'absolute', + right: -10, + }, + inputPassword: { + paddingRight: 30, + }, +}); + +export { PasswordInput }; diff --git a/web/account/password-input.css b/web/account/password-input.css --- a/web/account/password-input.css +++ b/web/account/password-input.css @@ -2,17 +2,10 @@ padding-right: 50px; } -.wrapper { +.button { position: absolute; right: 0; top: 0; -} - -.wrapper :hover { - background-color: var(--show-password-bg-hover); -} - -.button { margin: 7px; padding: 6px; border: 0; @@ -20,7 +13,10 @@ color: var(--fg); } -.fieldset { - all: unset; +.button:hover { + background-color: var(--show-password-bg-hover); +} + +.wrapper { position: relative; } diff --git a/web/account/password-input.react.js b/web/account/password-input.react.js --- a/web/account/password-input.react.js +++ b/web/account/password-input.react.js @@ -10,11 +10,13 @@ type PasswordInputProps = BaseInputProps; function PasswordInput(props: PasswordInputProps, ref): React.Node { - const [htmlInputType, setHtmlInputType] = React.useState('password'); + const [htmlInputType, setHtmlInputType] = React.useState<'password' | 'text'>( + 'password', + ); const onToggleShowPassword = React.useCallback(() => { setHtmlInputType(oldType => (oldType === 'password' ? 'text' : 'password')); - }, [setHtmlInputType]); + }, []); const icon: Icon = React.useMemo( () => (htmlInputType === 'password' ? 'eye-open' : 'eye-closed'), @@ -22,7 +24,7 @@ ); return ( -
+
-
- -
-
+ + ); } diff --git a/web/modals/input.react.js b/web/modals/input.react.js --- a/web/modals/input.react.js +++ b/web/modals/input.react.js @@ -1,5 +1,6 @@ // @flow +import classNames from 'classnames'; import * as React from 'react'; import css from './input.css'; @@ -38,11 +39,13 @@ ); } + const inputClassName = classNames(css.input, className); + return ( <> {label}