Skip to content

Commit c9f4292

Browse files
authored
Merge pull request #6501 from anthony-hull/anthony--toggle-show-password2
add show password toggle to secureTextInput
2 parents ff3625f + 44b1789 commit c9f4292

File tree

5 files changed

+83
-22
lines changed

5 files changed

+83
-22
lines changed

assets/images/eye-disabled.svg

Lines changed: 15 additions & 0 deletions
Loading

src/components/ExpensiTextInput/BaseExpensiTextInput.js

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import _ from 'underscore';
22
import React, {Component} from 'react';
33
import {
4-
Animated, TextInput, View, TouchableWithoutFeedback,
4+
Animated, TextInput, View, TouchableWithoutFeedback, Pressable,
55
} from 'react-native';
66
import Str from 'expensify-common/lib/str';
77
import ExpensiTextInputLabel from './ExpensiTextInputLabel';
88
import {propTypes, defaultProps} from './baseExpensiTextInputPropTypes';
99
import themeColors from '../../styles/themes/default';
1010
import styles from '../../styles/styles';
11+
import Icon from '../Icon';
12+
import * as Expensicons from '../Icon/Expensicons';
1113
import InlineErrorText from '../InlineErrorText';
1214

1315
const ACTIVE_LABEL_TRANSLATE_Y = -12;
@@ -31,6 +33,7 @@ class BaseExpensiTextInput extends Component {
3133
labelTranslateX: new Animated.Value(activeLabel
3234
? ACTIVE_LABEL_TRANSLATE_X(props.translateX) : INACTIVE_LABEL_TRANSLATE_X),
3335
labelScale: new Animated.Value(activeLabel ? ACTIVE_LABEL_SCALE : INACTIVE_LABEL_SCALE),
36+
passwordHidden: props.secureTextEntry,
3437
};
3538

3639
this.input = null;
@@ -39,6 +42,7 @@ class BaseExpensiTextInput extends Component {
3942
this.onFocus = this.onFocus.bind(this);
4043
this.onBlur = this.onBlur.bind(this);
4144
this.setValue = this.setValue.bind(this);
45+
this.togglePasswordVisibility = this.togglePasswordVisibility.bind(this);
4246
}
4347

4448
componentDidMount() {
@@ -145,6 +149,10 @@ class BaseExpensiTextInput extends Component {
145149
]).start();
146150
}
147151

152+
togglePasswordVisibility() {
153+
this.setState(prevState => ({passwordHidden: !prevState.passwordHidden}));
154+
}
155+
148156
render() {
149157
const inputProps = _.omit(this.props, _.keys(propTypes));
150158
const hasLabel = Boolean(this.props.label.length);
@@ -167,8 +175,8 @@ class BaseExpensiTextInput extends Component {
167175
{hasLabel ? (
168176
<>
169177
{/* Adding this background to the label only for multiline text input,
170-
to prevent text overlaping with label when scrolling */}
171-
{this.props.multiline && <View style={styles.expensiTextInputLabelBackground} />}
178+
to prevent text overlapping with label when scrolling */}
179+
{this.props.multiline && <View style={styles.expensiTextInputLabelBackground} pointerEvents="none" />}
172180
<ExpensiTextInputLabel
173181
label={this.props.label}
174182
labelTranslateX={
@@ -181,25 +189,40 @@ class BaseExpensiTextInput extends Component {
181189
/>
182190
</>
183191
) : null}
184-
<TextInput
185-
ref={(ref) => {
186-
if (typeof this.props.innerRef === 'function') { this.props.innerRef(ref); }
187-
this.input = ref;
188-
}}
189-
// eslint-disable-next-line
190-
{...inputProps}
191-
value={this.value}
192-
placeholder={(this.state.isFocused || !this.props.label) ? this.props.placeholder : null}
193-
placeholderTextColor={themeColors.placeholderText}
194-
underlineColorAndroid="transparent"
195-
style={[this.props.inputStyle, !hasLabel && styles.pv0]}
196-
multiline={this.props.multiline}
197-
onFocus={this.onFocus}
198-
onBlur={this.onBlur}
199-
onChangeText={this.setValue}
200-
onPressOut={this.props.onPress}
201-
translateX={this.props.translateX}
202-
/>
192+
<View style={[styles.expensiTextInputAndIconContainer]}>
193+
<TextInput
194+
ref={(ref) => {
195+
if (typeof this.props.innerRef === 'function') { this.props.innerRef(ref); }
196+
this.input = ref;
197+
}}
198+
// eslint-disable-next-line
199+
{...inputProps}
200+
value={this.value}
201+
placeholder={(this.state.isFocused || !this.props.label) ? this.props.placeholder : null}
202+
placeholderTextColor={themeColors.placeholderText}
203+
underlineColorAndroid="transparent"
204+
style={[this.props.inputStyle, styles.flex1, styles.w100, !hasLabel && styles.pv0, this.props.secureTextEntry && styles.pr2]}
205+
multiline={this.props.multiline}
206+
onFocus={this.onFocus}
207+
onBlur={this.onBlur}
208+
onChangeText={this.setValue}
209+
secureTextEntry={this.state.passwordHidden}
210+
onPressOut={this.props.onPress}
211+
translateX={this.props.translateX}
212+
/>
213+
{this.props.secureTextEntry && (
214+
<Pressable
215+
accessibilityRole="button"
216+
style={styles.secureInputEyeButton}
217+
onPress={this.togglePasswordVisibility}
218+
>
219+
<Icon
220+
src={this.state.passwordHidden ? Expensicons.Eye : Expensicons.EyeDisabled}
221+
fill={themeColors.icon}
222+
/>
223+
</Pressable>
224+
)}
225+
</View>
203226
</View>
204227
</TouchableWithoutFeedback>
205228
</View>

src/components/Icon/Expensicons.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import Download from '../../../assets/images/download.svg';
2121
import Emoji from '../../../assets/images/emoji.svg';
2222
import Exclamation from '../../../assets/images/exclamation.svg';
2323
import Eye from '../../../assets/images/eye.svg';
24+
import EyeDisabled from '../../../assets/images/eye-disabled.svg';
2425
import ExpensifyCard from '../../../assets/images/expensifycard.svg';
2526
import Gallery from '../../../assets/images/gallery.svg';
2627
import Gear from '../../../assets/images/gear.svg';
@@ -87,6 +88,7 @@ export {
8788
Emoji,
8889
Exclamation,
8990
Eye,
91+
EyeDisabled,
9092
ExpensifyCard,
9193
Gallery,
9294
Gear,

src/styles/styles.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ const styles = {
583583
componentHeightLarge: {
584584
height: variables.componentSizeLarge,
585585
},
586+
586587
expensiTextInputContainer: {
587588
flex: 1,
588589
borderWidth: 1,
@@ -593,6 +594,7 @@ const styles = {
593594
backgroundColor: themeColors.componentBG,
594595
overflow: 'hidden',
595596
},
597+
596598
expensiTextInputLabel: {
597599
position: 'absolute',
598600
left: 11.5,
@@ -602,6 +604,7 @@ const styles = {
602604
fontFamily: fontFamily.GTA,
603605
width: '100%',
604606
},
607+
605608
expensiTextInputLabelBackground: {
606609
position: 'absolute',
607610
top: 0,
@@ -611,16 +614,19 @@ const styles = {
611614
borderTopRightRadius: variables.componentBorderRadiusNormal,
612615
borderTopLeftRadius: variables.componentBorderRadiusNormal,
613616
},
617+
614618
expensiTextInputLabelDesktop: {
615619
transformOrigin: 'left center',
616620
},
621+
617622
expensiTextInputLabelTransformation: (translateY, translateX, scale) => ({
618623
transform: [
619624
{translateY},
620625
{translateX},
621626
{scale},
622627
],
623628
}),
629+
624630
expensiTextInput: {
625631
fontFamily: fontFamily.GTA,
626632
fontSize: variables.fontSizeNormal,
@@ -630,13 +636,25 @@ const styles = {
630636
paddingBottom: 8,
631637
paddingHorizontal: 11.5,
632638
borderRadius: variables.componentBorderRadiusNormal,
639+
},
640+
641+
expensiTextInputAndIconContainer: {
633642
zIndex: -1,
643+
flexDirection: 'row',
634644
},
645+
635646
expensiTextInputDesktop: addOutlineWidth({}, 0),
647+
636648
expensiTextInputAndroid: left => ({
637649
padding: 0,
638650
left,
639651
}),
652+
653+
secureInputEyeButton: {
654+
paddingRight: 11.5,
655+
justifyContent: 'center',
656+
},
657+
640658
textInput: {
641659
backgroundColor: themeColors.componentBG,
642660
borderRadius: variables.componentBorderRadiusNormal,

web/index.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
outline: 0;
4141
box-shadow: 0px 0px 0px 1px #0185ff;
4242
}
43+
::-ms-reveal {
44+
display: none;
45+
}
4346
</style>
4447
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
4548
<link rel="shortcut icon" id="favicon" href="/favicon.png">

0 commit comments

Comments
 (0)