Files
biiproject-kit-v1/mobile/components/Input.tsx
T

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',
},
});