122 lines
3.6 KiB
TypeScript
122 lines
3.6 KiB
TypeScript
import { ThemedText } from "@/components/ThemedText";
|
|
import { Fonts } from "@/constants/Fonts";
|
|
import { Ionicons } from "@expo/vector-icons";
|
|
import { TextInput as RNTextInput, TextInputProps as RNTextInputProps, StyleProp, StyleSheet, TextStyle, TouchableOpacity, View, ViewStyle } from "react-native";
|
|
|
|
interface CustomTextInputProps {
|
|
label: string;
|
|
placeholder: string;
|
|
value: string;
|
|
onChangeText: (text: string) => void;
|
|
showPassword?: boolean;
|
|
setShowPassword?: (showPassword: boolean) => void;
|
|
setError?: (error: string) => void;
|
|
type?: 'default' | 'password';
|
|
containerStyle?: StyleProp<ViewStyle>;
|
|
style?: StyleProp<TextStyle>;
|
|
error?: string;
|
|
}
|
|
|
|
type TextInputProps = RNTextInputProps & CustomTextInputProps;
|
|
|
|
const TextInput = ({
|
|
type = 'default',
|
|
label,
|
|
placeholder,
|
|
value,
|
|
onChangeText,
|
|
setError,
|
|
showPassword,
|
|
setShowPassword,
|
|
error,
|
|
style,
|
|
containerStyle,
|
|
...props
|
|
}: TextInputProps) => {
|
|
|
|
return (
|
|
<View style={[styles.inputContainer, containerStyle]}>
|
|
<View className="w-full flex flex-row justify-between">
|
|
<ThemedText style={styles.inputLabel}>
|
|
{label}
|
|
</ThemedText>
|
|
{
|
|
error &&
|
|
<ThemedText color="bgSecondary" size="xxs">
|
|
{error}
|
|
</ThemedText>
|
|
}
|
|
</View>
|
|
|
|
<View style={styles.inputTextContainer}>
|
|
<RNTextInput
|
|
style={[styles.textInput, style]}
|
|
placeholder={placeholder}
|
|
placeholderTextColor={Fonts['placeholderTextColor']}
|
|
value={value}
|
|
onChangeText={onChangeText}
|
|
secureTextEntry={type === 'password' ? !showPassword : undefined}
|
|
{...props}
|
|
/>
|
|
{
|
|
type === 'password' &&
|
|
<TouchableOpacity
|
|
style={styles.eyeIcon}
|
|
onPress={() => {
|
|
if (setShowPassword) {
|
|
setShowPassword(!showPassword);
|
|
}
|
|
}}
|
|
>
|
|
<Ionicons
|
|
name={showPassword ? 'eye' : 'eye-off'}
|
|
size={20}
|
|
color="#666"
|
|
/>
|
|
</TouchableOpacity>
|
|
}
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
inputContainer: {
|
|
marginBottom: 20,
|
|
},
|
|
inputLabel: {
|
|
fontSize: Fonts['sm'],
|
|
color: Fonts['textPrimary'],
|
|
fontWeight: Fonts['bold'],
|
|
fontFamily: Fonts['sfPro'],
|
|
marginBottom: 8,
|
|
marginLeft: 8,
|
|
},
|
|
textInput: {
|
|
borderRadius: Fonts['xs'],
|
|
paddingHorizontal: Fonts['base'],
|
|
paddingVertical: Fonts['sm'],
|
|
fontSize: Fonts['sm'],
|
|
lineHeight: Fonts['base'],
|
|
textAlignVertical: 'center',
|
|
backgroundColor: Fonts['bgInput'],
|
|
color: Fonts['textSecondary'],
|
|
fontFamily: Fonts['inter'],
|
|
paddingRight: 48, // Make space for the eye icon
|
|
},
|
|
inputTextContainer: {
|
|
position: 'relative',
|
|
},
|
|
eyeIcon: {
|
|
position: 'absolute',
|
|
right: 12,
|
|
top: '50%',
|
|
transform: [{ translateY: -10 }], // Half of the icon's height (20/2 = 10)
|
|
height: 20,
|
|
width: 20,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
})
|
|
|
|
export default TextInput; |