import React, { useEffect, useMemo, useRef, useState } from 'react'; import { TextInput as RNTextInput, View, TextInputProps as RNTextInputProps, TouchableOpacity, StyleSheet, Text } from 'react-native'; import Animated, { interpolate, interpolateColor, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated'; import { opacity } from '../../utilities'; import type { FCCWD, TextInputProps } from '../../types'; import { applyDefaults } from '../../core/KitraProvider'; const AnimatedTextInput = Animated.createAnimatedComponent(RNTextInput); const TextInput: FCCWD = ( { theme, typography, inputStyle, editable = true, size = 'medium', helperText = '', variant = 'filled', labelContainerStyle, containerStyle, count = false, onChangeText, label, inputContainerStyle, labelStyle, helperTextStyle, error = false, errorMessage, left, right, labelColor = { focus: theme?.primary, default: theme?.primary }, onFocus, onEndEditing, ...props }, ) => { const inputRef = useRef(null); const [counts, setCounts] = useState(0); const textInputOffset = useSharedValue(props.defaultValue || props.placeholder || props.value ? 0 : 1); const fontStyles = { large: typography?.body.regular, medium: typography?.body.sregular, small: typography?.body.xsregular, }; const sizeStyles = { large: { padding: 15, height: 51, }, medium: { padding: 12, height: 42, }, small: { padding: 10, height: 36, }, }; const labelStyles = { large: { focused: typography?.body.regular, default: typography?.body.sregular, }, medium: { focused: typography?.body.sregular, default: typography?.body.xsregular, }, small: { focused: typography?.body.xsregular, default: typography?.body.xxsregular, }, }; // label'ın konum ve fontsize animasyonu const labelPositionAnimation = useAnimatedStyle(() => { const topInterpolate = interpolate( textInputOffset.value, [0, 1], [variant === 'filled' ? 2 : -labelStyles[size].focused.lineHeight + labelStyles[size].focused.lineHeight / 2, sizeStyles[size].padding], ); return { top: topInterpolate, }; }); const borderAnimation = useAnimatedStyle(() => { const topInterpolate = interpolateColor( textInputOffset.value, [0, 1], [theme?.primary || '#000000', theme?.grey || '#FFFFFF'], ); return { borderColor: topInterpolate, }; }); const labelFontAnimation = useAnimatedStyle(() => { const fontSize = interpolate( textInputOffset.value, [0, 1], [labelStyles[size].default.fontSize, labelStyles[size].focused.fontSize], ); const lineHeight = interpolate( textInputOffset.value, [0, 1], [labelStyles[size].default.lineHeight, labelStyles[size].focused.lineHeight], ); const color = interpolateColor( textInputOffset.value, [0, 1], // @ts-ignore [error ? theme?.error : labelColor.focus || '#000000', error ? theme?.error : labelColor.default || '#FFFFFF'], ); return { fontSize, lineHeight, color, }; }); useEffect(() => { if (props.value) { setCounts(props.value?.length ? props.value?.length : 0); textInputOffset.value = props.value?.length || props.defaultValue?.length ? withTiming(0) : withTiming(1); } else if (!props.defaultValue?.length) { textInputOffset.value = withTiming(1); } }, [props.value]); useEffect(() => { setCounts(props.defaultValue ? props.defaultValue.length : 0); }, []); const onFocusInput = () => { textInputOffset.value = withTiming(0); }; const onEndEditingInput = () => { textInputOffset.value = (counts === 0) ? withTiming(1) : withTiming(0); }; return ( {left && left} { setCounts(event?.length || 0); onChangeText && onChangeText(event); }} onFocus={x => { onFocusInput(); onFocus?.(x); }} onEndEditing={x => { onEndEditingInput(); onEndEditing?.(x); }} {...props} /> {label ? ( inputRef.current?.focus()} activeOpacity={0.9}> {label} ) : null } {right && right} {/* @ts-ignore */} {error ? `${errorMessage || ''}` : `${helperText}`} {/* @ts-ignore */} {count ? {`${counts}/${props.maxLength}`} : null} ); }; const styles = StyleSheet.create({ inputContainer: { alignItems: 'center', }, helperContainer: { flexDirection: 'row', paddingHorizontal: 5, justifyContent: 'space-between', }, }); export default applyDefaults(TextInput);