import React from 'react'; import { TextInput, Animated, Platform } from 'react-native'; import styled from 'styled-components/native'; import { border, flex, space, color, flexbox, layout, typography, } from 'styled-system'; import { customBorder, customBackground, customOutline, customLayout, customExtra, customShadow, customTypography, } from '../../../utils/customProps'; import Box from '../Box'; import Text from '../Text'; import Flex from '../Flex'; import type { IInputProps } from './types'; import { InputRightAddon, InputGroup, InputLeftAddon } from './InputGroup'; import { useThemeProps, useToken } from '../../../hooks'; import { themeTools } from '../../../theme'; import { useHover } from '@react-native-aria/interactions'; import { FormControlContext, IFormControlContext, } from '../../composites/FormControl'; const StyledInput = styled(TextInput)( flex, color, space, layout, flexbox, border, typography, customBorder, customBackground, customOutline, customShadow, customExtra, customTypography, customLayout ); const Input = ( { style, placeholder, errorMessage, _errorMessage, // isRequired, isFullWidth, onFocus, onBlur, ariaLabel, accessibilityLabel, InputLeftElement, InputRightElement, type, w, width, h, height, m, mr, ml, mt, mb, mx, my, label, _label, placeholderTextColor, ...props }: IInputProps, ref: any ) => { const formControlContext: IFormControlContext = React.useContext( FormControlContext ); const layoutProps = { w, width, m, mr, ml, mt, mb, mx, my, }; const [isFocused, setIsFocused] = React.useState(false); const handleFocus = (focusState: boolean, callback: any) => { setIsFocused(focusState); callback(); }; let placeholderColor = useToken( 'colors', (placeholderTextColor as string) ?? 'gray.400' ); if (typeof placeholderColor !== 'string') { placeholderColor = placeholderTextColor; } const { isInvalid, isDisabled, isReadOnly, borderColor: borderColorFromProps, fontSize, borderWidth, focusBorderColor, errorBorderColor, hoverBorderColor, borderBottomWidth, _errorMessageBaseProps, ...newProps } = useThemeProps('Input', { ...formControlContext, ...props }); const computedProps = { display: 'flex', flexDirection: 'row', h, height, }; let [, rem] = themeTools.extractInObject(newProps, [ 'p', 'px', 'py', 'pt', 'pb', 'pl', 'pr', ]); const slideAnim = React.useRef(new Animated.Value(0)).current; const slideIn = () => { Animated.timing(slideAnim, { toValue: 0, duration: 200, useNativeDriver: Platform.OS !== 'web', }).start(); }; const slideOut = () => { Animated.timing(slideAnim, { // NOTE: Below 3 value are (padding + half of font + buffer) toValue: -(12 + Math.floor(fontSize / 2) + 2), duration: 200, useNativeDriver: Platform.OS !== 'web', }).start(); }; const _ref = React.useRef(null); const { isHovered } = useHover({}, _ref); let updatedBorderColor = borderColorFromProps; if (isHovered) updatedBorderColor = hoverBorderColor; else if (isFocused) updatedBorderColor = focusBorderColor; else if (isInvalid) updatedBorderColor = errorBorderColor; const focusStyle = { shadow: 3, shadowColor: '#2563EB', }; return ( {InputLeftElement ? ( {InputLeftElement} ) : null} {isFocused && label && ( {label} )} { e.persist(); props.onKeyPress && props.onKeyPress(e); }} onFocus={(e) => { slideOut(); handleFocus(true, onFocus ? () => onFocus(e) : () => {}); }} onBlur={(e) => { // TODO: animation not happening because of component rerender e.nativeEvent.text && slideIn(); handleFocus(false, onBlur ? () => onBlur(e) : () => {}); }} placeholder={isFocused && label ? '' : placeholder} placeholderTextColor={placeholderColor} editable={isDisabled || isReadOnly ? false : true} // borderRadius={50} //Remove variant props from StyledInput borderWidth={undefined} {...(Platform.OS === 'web' ? { disabled: isDisabled, cursor: isDisabled ? 'not-allowed' : 'auto', } : {})} style={[ Platform.OS === 'web' && { // @ts-ignore outline: 'none', }, ]} ref={ref} /> {InputRightElement ? ( {InputRightElement} ) : null} {isInvalid && errorMessage ? ( {errorMessage} ) : null} ); }; //-------------------------------- InputGroup and other Child components ------------------------------- export { InputRightAddon, InputGroup, InputLeftAddon }; export type { IInputProps }; export default React.memo(React.forwardRef(Input));