190 lines
4.5 KiB
TypeScript
190 lines
4.5 KiB
TypeScript
import React from 'react';
|
|
import { StyleProp, StyleSheet, Text, TextInputProps, TextInput as RNTextInput, TextStyle, View, ViewStyle } from 'react-native';
|
|
import Touchable from 'react-native-platform-touchable';
|
|
|
|
import sharedStyles from '../views/Styles';
|
|
import TextInput from '../presentation/TextInput';
|
|
import { themes } from '../constants/colors';
|
|
import { CustomIcon } from '../lib/Icons';
|
|
import ActivityIndicator from './ActivityIndicator';
|
|
|
|
const styles = StyleSheet.create({
|
|
error: {
|
|
...sharedStyles.textAlignCenter,
|
|
paddingTop: 5
|
|
},
|
|
inputContainer: {
|
|
marginBottom: 10
|
|
},
|
|
label: {
|
|
marginBottom: 10,
|
|
fontSize: 14,
|
|
...sharedStyles.textSemibold
|
|
},
|
|
input: {
|
|
...sharedStyles.textRegular,
|
|
height: 48,
|
|
fontSize: 16,
|
|
padding: 14,
|
|
borderWidth: StyleSheet.hairlineWidth,
|
|
borderRadius: 2
|
|
},
|
|
inputIconLeft: {
|
|
paddingLeft: 45
|
|
},
|
|
inputIconRight: {
|
|
paddingRight: 45
|
|
},
|
|
wrap: {
|
|
position: 'relative'
|
|
},
|
|
iconContainer: {
|
|
position: 'absolute',
|
|
top: 14
|
|
},
|
|
iconLeft: {
|
|
left: 15
|
|
},
|
|
iconRight: {
|
|
right: 15
|
|
}
|
|
});
|
|
|
|
export interface IRCTextInputProps extends TextInputProps {
|
|
label?: string;
|
|
error?: {
|
|
error: any;
|
|
reason: any;
|
|
};
|
|
loading?: boolean;
|
|
containerStyle?: StyleProp<ViewStyle>;
|
|
inputStyle?: StyleProp<TextStyle>;
|
|
inputRef?: React.Ref<RNTextInput>;
|
|
testID?: string;
|
|
iconLeft?: string;
|
|
iconRight?: string;
|
|
left?: JSX.Element;
|
|
onIconRightPress?(): void;
|
|
theme: string;
|
|
}
|
|
|
|
export default class RCTextInput extends React.PureComponent<IRCTextInputProps, any> {
|
|
static defaultProps = {
|
|
error: {},
|
|
theme: 'light'
|
|
};
|
|
|
|
state = {
|
|
showPassword: false
|
|
};
|
|
|
|
get iconLeft() {
|
|
const { testID, iconLeft, theme } = this.props;
|
|
return (
|
|
<CustomIcon
|
|
name={iconLeft}
|
|
testID={testID ? `${testID}-icon-left` : null}
|
|
style={[styles.iconContainer, styles.iconLeft, { color: themes[theme].bodyText }]}
|
|
size={20}
|
|
/>
|
|
);
|
|
}
|
|
|
|
get iconRight() {
|
|
const { iconRight, onIconRightPress, theme } = this.props;
|
|
return (
|
|
<Touchable onPress={onIconRightPress} style={[styles.iconContainer, styles.iconRight]}>
|
|
<CustomIcon name={iconRight} style={{ color: themes[theme].bodyText }} size={20} />
|
|
</Touchable>
|
|
);
|
|
}
|
|
|
|
get iconPassword() {
|
|
const { showPassword } = this.state;
|
|
const { testID, theme } = this.props;
|
|
return (
|
|
<Touchable onPress={this.tooglePassword} style={[styles.iconContainer, styles.iconRight]}>
|
|
<CustomIcon
|
|
name={showPassword ? 'unread-on-top' : 'unread-on-top-disabled'}
|
|
testID={testID ? `${testID}-icon-right` : null}
|
|
style={{ color: themes[theme].auxiliaryText }}
|
|
size={20}
|
|
/>
|
|
</Touchable>
|
|
);
|
|
}
|
|
|
|
get loading() {
|
|
const { theme } = this.props;
|
|
// @ts-ignore
|
|
return <ActivityIndicator style={[styles.iconContainer, styles.iconRight, { color: themes[theme].bodyText }]} />;
|
|
}
|
|
|
|
tooglePassword = () => {
|
|
this.setState((prevState: any) => ({ showPassword: !prevState.showPassword }));
|
|
};
|
|
|
|
render() {
|
|
const { showPassword } = this.state;
|
|
const {
|
|
label,
|
|
left,
|
|
error,
|
|
loading,
|
|
secureTextEntry,
|
|
containerStyle,
|
|
inputRef,
|
|
iconLeft,
|
|
iconRight,
|
|
inputStyle,
|
|
testID,
|
|
placeholder,
|
|
theme,
|
|
...inputProps
|
|
} = this.props;
|
|
const { dangerColor } = themes[theme];
|
|
return (
|
|
<View style={[styles.inputContainer, containerStyle]}>
|
|
{label ? (
|
|
<Text style={[styles.label, { color: themes[theme].titleText }, error?.error && { color: dangerColor }]}>{label}</Text>
|
|
) : null}
|
|
<View style={styles.wrap}>
|
|
<TextInput
|
|
style={[
|
|
styles.input,
|
|
iconLeft && styles.inputIconLeft,
|
|
(secureTextEntry || iconRight) && styles.inputIconRight,
|
|
{
|
|
backgroundColor: themes[theme].backgroundColor,
|
|
borderColor: themes[theme].separatorColor,
|
|
color: themes[theme].titleText
|
|
},
|
|
error?.error && {
|
|
color: dangerColor,
|
|
borderColor: dangerColor
|
|
},
|
|
inputStyle
|
|
]}
|
|
ref={inputRef}
|
|
autoCorrect={false}
|
|
autoCapitalize='none'
|
|
underlineColorAndroid='transparent'
|
|
secureTextEntry={secureTextEntry && !showPassword}
|
|
testID={testID}
|
|
accessibilityLabel={placeholder}
|
|
placeholder={placeholder}
|
|
theme={theme}
|
|
{...inputProps}
|
|
/>
|
|
{iconLeft ? this.iconLeft : null}
|
|
{iconRight ? this.iconRight : null}
|
|
{secureTextEntry ? this.iconPassword : null}
|
|
{loading ? this.loading : null}
|
|
{left}
|
|
</View>
|
|
{error && error.reason ? <Text style={[styles.error, { color: dangerColor }]}>{error.reason}</Text> : null}
|
|
</View>
|
|
);
|
|
}
|
|
}
|