Page MenuHomePhabricator

D5453.id17802.diff
No OneTemporary

D5453.id17802.diff

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<Props> {
usernameInput: ?TextInput;
- passwordInput: ?TextInput;
+ passwordInput: ?PasswordInput;
componentDidMount() {
this.attemptToFetchCredentials();
@@ -132,14 +133,14 @@
color="#555"
style={styles.icon}
/>
- <TextInput
- style={styles.input}
+ <PasswordInput
+ style={[styles.input, styles.inputPassword]}
value={this.passwordInputText}
onChangeText={this.onChangePasswordInputText}
placeholder="Password"
- secureTextEntry={true}
textContentType="password"
autoComplete="password"
+ autoCapitalize="none"
returnKeyType="go"
blurOnSubmit={false}
onSubmitEditing={this.onSubmit}
@@ -170,7 +171,7 @@
this.usernameInput.focus();
};
- passwordInputRef: (passwordInput: ?TextInput) => void = passwordInput => {
+ passwordInputRef: (passwordInput: ?PasswordInput) => void = passwordInput => {
this.passwordInput = passwordInput;
};
@@ -345,6 +346,9 @@
input: {
paddingLeft: 35,
},
+ inputPassword: {
+ paddingRight: 40,
+ },
row: {
marginHorizontal: 24,
},
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,77 @@
+// @flow
+
+import invariant from 'invariant';
+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<typeof BaseTextInput>;
+
+type State = {
+ +secureTextEntry: boolean,
+};
+
+class PasswordInput extends React.PureComponent<Props, State> {
+ wrappedTextInput: ?TextInput;
+ constructor(props: Props) {
+ super(props);
+ this.state = { secureTextEntry: true };
+ }
+
+ render(): React.Node {
+ return (
+ <View>
+ <TextInput
+ {...this.props}
+ secureTextEntry={this.state.secureTextEntry}
+ ref={this.wrappedTextInputRef}
+ />
+ <Button
+ onPress={() => {
+ this.setState(state => ({
+ secureTextEntry: !state.secureTextEntry,
+ }));
+ }}
+ iosFormat="highlight"
+ androidFormat="highlight"
+ iosHighlightUnderlayColor="#A0A0A0DD"
+ iosActiveOpacity={0.85}
+ topStyle={styles.button}
+ >
+ <SWMansionIcon
+ name={this.state.secureTextEntry ? 'eye-open' : 'eye-closed'}
+ size={22}
+ color="#555"
+ />
+ </Button>
+ </View>
+ );
+ }
+
+ wrappedTextInputRef: (
+ wrappedTextInput: ?TextInput,
+ ) => void = wrappedTextInput => {
+ this.wrappedTextInput = wrappedTextInput;
+ };
+
+ focus() {
+ invariant(this.wrappedTextInput, 'ref should exist');
+ this.wrappedTextInput.focus();
+ }
+}
+
+const styles = StyleSheet.create({
+ button: {
+ borderRadius: 21,
+ bottom: 0,
+ margin: 2,
+ padding: 8,
+ position: 'absolute',
+ right: 10,
+ },
+});
+
+export { PasswordInput };
diff --git a/web/account/log-in-form.react.js b/web/account/log-in-form.react.js
--- a/web/account/log-in-form.react.js
+++ b/web/account/log-in-form.react.js
@@ -26,6 +26,7 @@
import { useSelector } from '../redux/redux-utils';
import { webLogInExtraInfoSelector } from '../selectors/account-selectors';
import css from './log-in-form.css';
+import PasswordInput from './password-input.react';
const loadingStatusSelector = createLoadingStatusSelector(logInActionTypes);
function LoginForm(): React.Node {
@@ -139,9 +140,7 @@
<div>
<div className={css['form-title']}>Password</div>
<div className={css['form-content']}>
- <Input
- type="password"
- placeholder="Password"
+ <PasswordInput
value={password}
onChange={onPasswordChange}
disabled={inputDisabled}
diff --git a/web/account/password-input.css b/web/account/password-input.css
new file mode 100644
--- /dev/null
+++ b/web/account/password-input.css
@@ -0,0 +1,22 @@
+.iconWrapper {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+}
+
+.iconWrapper :hover {
+ background-color: var(--show-password-background-hover);
+}
+
+.iconButtonWrapper {
+ margin: 7px;
+ padding: 6px;
+ padding-bottom: 2px;
+ border: 0;
+ border-radius: 50%;
+}
+
+.fieldsetWrapper {
+ all: unset;
+ position: relative;
+}
diff --git a/web/account/password-input.react.js b/web/account/password-input.react.js
new file mode 100644
--- /dev/null
+++ b/web/account/password-input.react.js
@@ -0,0 +1,51 @@
+// @flow
+
+import * as React from 'react';
+
+import Input from '../modals/input.react';
+import SWMansionIcon from '../SWMansionIcon.react';
+import type { Icon } from '../SWMansionIcon.react';
+import css from './password-input.css';
+
+type Props = {
+ +value: string,
+ +onChange: (value: SyntheticEvent<HTMLInputElement>) => mixed,
+ +onBlur?: (value: SyntheticEvent<HTMLInputElement>) => mixed,
+ +disabled?: boolean,
+ +label?: string,
+ +id?: string,
+};
+
+function PasswordInput(props: Props, ref): React.Node {
+ const [type, setType] = React.useState('password');
+ const onToggleShowPassword: () => void = () => {
+ setType(oldType => (oldType === 'password' ? 'text' : 'password'));
+ };
+
+ const getIcon: () => Icon = () => {
+ return type === 'password' ? 'eye-open' : 'eye-closed';
+ };
+
+ return (
+ <fieldset className={css.fieldsetWrapper}>
+ <Input placeholder="Password" type={type} {...props} ref={ref} />
+ <div className={css.iconWrapper}>
+ <div
+ className={css.iconButtonWrapper}
+ onClick={() => {
+ onToggleShowPassword();
+ }}
+ >
+ <SWMansionIcon size="24px" icon={getIcon()} />
+ </div>
+ </div>
+ </fieldset>
+ );
+}
+
+const ForwardedPasswordInput: React.AbstractComponent<
+ Props,
+ HTMLInputElement,
+> = React.forwardRef<Props, HTMLInputElement>(PasswordInput);
+
+export default ForwardedPasswordInput;
diff --git a/web/modals/input.css b/web/modals/input.css
--- a/web/modals/input.css
+++ b/web/modals/input.css
@@ -20,4 +20,5 @@
line-height: var(--line-height-text);
color: var(--fg);
border-radius: 4px;
+ padding-right: 50px;
}
diff --git a/web/theme.css b/web/theme.css
--- a/web/theme.css
+++ b/web/theme.css
@@ -180,4 +180,5 @@
--compose-subchannel-label-color: var(--shades-black-60);
--compose-subchannel-mark-color: var(--violet-light-100);
--enum-option-icon-color: var(--violet-dark-100);
+ --show-password-background-hover: var(--shades-black-70);
}

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 16, 3:23 PM (21 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2498118
Default Alt Text
D5453.id17802.diff (7 KB)

Event Timeline