bw-expo-app/components/forms/form-fields/number-input.tsx

113 lines
2.8 KiB
TypeScript

import { TextInput, View, StyleSheet } from 'react-native';
import { ThemedText } from '@/components/themed-text';
import { useThemeColor } from '@/hooks/use-theme-color';
import { FormFieldSchema } from '@/lib/types/template-run';
interface NumberInputFieldProps {
field: FormFieldSchema;
value: number | string;
onChange: (value: number) => void;
error?: string;
}
export function NumberInputField({ field, value, onChange, error }: NumberInputFieldProps) {
const textColor = useThemeColor({}, 'text');
const borderColor = useThemeColor({}, 'border');
const errorColor = useThemeColor({}, 'error');
const placeholderColor = useThemeColor({}, 'textPlaceholder');
const backgroundColor = useThemeColor({}, 'background');
const handleChange = (text: string) => {
const num = parseFloat(text);
if (!isNaN(num)) {
onChange(num);
} else if (text === '') {
onChange(0);
}
};
return (
<View style={styles.container}>
{field.label && (
<ThemedText style={styles.label}>
{field.label}
{field.required && <ThemedText style={[styles.required, { color: errorColor }]}> *</ThemedText>}
</ThemedText>
)}
<TextInput
style={[
styles.input,
{
color: textColor,
borderColor: error ? errorColor : borderColor,
backgroundColor,
}
]}
value={value?.toString() || ''}
onChangeText={handleChange}
placeholder={field.placeholder}
placeholderTextColor={placeholderColor}
keyboardType="numeric"
maxLength={10}
/>
{field.description && (
<ThemedText style={styles.description}>{field.description}</ThemedText>
)}
{error && (
<ThemedText style={[styles.errorText, { color: errorColor }]}>
{error}
</ThemedText>
)}
{(field.min !== undefined || field.max !== undefined) && (
<ThemedText style={styles.hint}>
{field.min !== undefined && field.max !== undefined
? `范围: ${field.min} - ${field.max}`
: field.min !== undefined
? `最小值: ${field.min}`
: `最大值: ${field.max}`}
</ThemedText>
)}
</View>
);
}
const styles = StyleSheet.create({
container: {
marginBottom: 16,
},
label: {
fontSize: 16,
fontWeight: '600',
marginBottom: 8,
},
required: {
fontSize: 16,
fontWeight: '600',
},
input: {
borderWidth: 1,
borderRadius: 8,
paddingHorizontal: 12,
paddingVertical: 10,
fontSize: 16,
minHeight: 44,
},
description: {
fontSize: 12,
opacity: 0.7,
marginTop: 4,
},
errorText: {
fontSize: 12,
marginTop: 4,
},
hint: {
fontSize: 12,
opacity: 0.6,
marginTop: 4,
},
});