145 lines
3.8 KiB
TypeScript
145 lines
3.8 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { View, TextInput, Text, StyleSheet, ViewStyle, TouchableOpacity, Platform } from 'react-native';
|
|
import { useAppTheme } from '../context/ThemeContext';
|
|
import { Feather } from '@expo/vector-icons';
|
|
|
|
interface InputProps {
|
|
label?: string;
|
|
placeholder?: string;
|
|
value: string;
|
|
onChangeText: (text: string) => void;
|
|
secureTextEntry?: boolean;
|
|
style?: ViewStyle;
|
|
keyboardType?: 'default' | 'email-address' | 'numeric' | 'phone-pad';
|
|
multiline?: boolean;
|
|
required?: boolean;
|
|
infoText?: string;
|
|
}
|
|
|
|
const LIME = '#C6F135';
|
|
|
|
export const Input: React.FC<InputProps> = ({
|
|
label,
|
|
placeholder,
|
|
value,
|
|
onChangeText,
|
|
secureTextEntry,
|
|
style,
|
|
keyboardType = 'default',
|
|
multiline = false,
|
|
required = false,
|
|
infoText
|
|
}) => {
|
|
const { colors, isDark } = useAppTheme();
|
|
const [isFocused, setIsFocused] = useState(false);
|
|
const [isPasswordVisible, setIsPasswordVisible] = useState(false);
|
|
|
|
const handleFocus = () => setIsFocused(true);
|
|
const handleBlur = () => setIsFocused(false);
|
|
|
|
const isSecure = secureTextEntry && !isPasswordVisible;
|
|
|
|
const bg = isDark ? '#1A1A1A' : '#F5F5F5';
|
|
const border = isDark ? '#2A2A2A' : '#EEEEEE';
|
|
|
|
return (
|
|
<View style={[styles.container, style]}>
|
|
{label && (
|
|
<View style={styles.labelRow}>
|
|
<Text style={[styles.label, { color: colors.textSecondary }]}>
|
|
{label}
|
|
{required && <Text style={{ color: '#EF4444' }}> *</Text>}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
<View style={[
|
|
styles.inputWrapper,
|
|
{
|
|
backgroundColor: bg,
|
|
borderColor: isFocused ? LIME : border,
|
|
},
|
|
multiline && { height: 120, borderRadius: 20, alignItems: 'flex-start', paddingTop: 16 }
|
|
]}>
|
|
<TextInput
|
|
style={[
|
|
styles.input,
|
|
{ color: colors.text, paddingRight: secureTextEntry ? 45 : 16 },
|
|
Platform.OS === 'web' && { outlineStyle: 'none' } as any
|
|
]}
|
|
placeholder={placeholder}
|
|
placeholderTextColor={isDark ? '#444' : '#BBB'}
|
|
value={value}
|
|
onChangeText={onChangeText}
|
|
secureTextEntry={isSecure}
|
|
onFocus={handleFocus}
|
|
onBlur={handleBlur}
|
|
keyboardType={keyboardType}
|
|
autoCapitalize="none"
|
|
multiline={multiline}
|
|
textAlignVertical={multiline ? 'top' : 'center'}
|
|
/>
|
|
|
|
{secureTextEntry && (
|
|
<TouchableOpacity
|
|
style={styles.eyeIcon}
|
|
onPress={() => setIsPasswordVisible(!isPasswordVisible)}
|
|
>
|
|
<Feather
|
|
name={isPasswordVisible ? "eye" : "eye-off"}
|
|
size={18}
|
|
color={isDark ? '#555' : '#AAA'}
|
|
/>
|
|
</TouchableOpacity>
|
|
)}
|
|
</View>
|
|
{infoText && <Text style={[styles.infoText, { color: isDark ? '#6B6B6B' : '#9B9B9B' }]}>{infoText}</Text>}
|
|
</View>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
marginBottom: 18,
|
|
width: '100%',
|
|
},
|
|
labelRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'flex-end',
|
|
marginBottom: 8,
|
|
},
|
|
label: {
|
|
fontSize: 11,
|
|
fontFamily: 'Outfit_700Bold',
|
|
letterSpacing: 1,
|
|
textTransform: 'uppercase',
|
|
},
|
|
inputWrapper: {
|
|
height: 56,
|
|
borderRadius: 14,
|
|
paddingLeft: 16,
|
|
borderWidth: 1.5,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
input: {
|
|
flex: 1,
|
|
fontSize: 15,
|
|
fontFamily: 'Outfit_500Medium',
|
|
height: '100%',
|
|
},
|
|
eyeIcon: {
|
|
position: 'absolute',
|
|
right: 15,
|
|
height: '100%',
|
|
justifyContent: 'center',
|
|
paddingHorizontal: 5,
|
|
},
|
|
infoText: {
|
|
fontSize: 12,
|
|
marginTop: 6,
|
|
marginLeft: 4,
|
|
fontFamily: 'Outfit_400Regular',
|
|
},
|
|
});
|