In order to make a custom input, I had to create an InputWrapper
to apply common style and add some animation behavior:
import React, { ReactElement, useState, useEffect } from 'react';import { StyleSheet, View, TouchableWithoutFeedbackProps,} from 'react-native';import Text from './Text';import { Colors, Theme } from '../constants';import { TouchableWithoutFeedback } from 'react-native-gesture-handler';interface Props extends TouchableWithoutFeedbackProps { label: string; value?: any; children: any; focus: boolean;}const styles = StyleSheet.create({ // ...});const InputWrapper = ({ label, value, children, focus, ...props}: Props): ReactElement => { const [show, setShow] = useState(false); useEffect(() => { setShow(focus || Boolean(value)); }, [focus, value]) return (<View style={[ styles.container, focus ? styles.containerFocus : {}, ]}><TouchableWithoutFeedback {...props}><View style={[ styles.wrapper, focus ? styles.wrapperFocus : {}, ]}><Text style={[ styles.label, show ? styles.labelActive : {}, ]}> {label}</Text> {show && children}</View></TouchableWithoutFeedback></View> );};export default InputWrapper;
I implemented the wrapper with the TextInput
native component:
import React, { ReactElement, useState, useRef } from 'react';import { TextInputProps, TextInput,} from 'react-native';import InputWrapper from './InputWrapper';import InputValue, { InputValueStyles } from './InputValue';interface Props extends TextInputProps { label?: string;}const Input = ({ label, value, ...props}: Props): ReactElement => { const [focus, setFocus] = useState(false); const input = useRef(null); const onWrapperPress = (): void => { setFocus(true); } const onInputFocus = (): void => { setFocus(true); } const onInputBlur = (): void => { setFocus(false); } return (<InputWrapper label={label} value={value} focus={focus} onPress={onWrapperPress}> {!focus && <InputValue value={value} />} {focus && <TextInput autoFocus={focus} style={InputValueStyles.input} value={value} onFocus={onInputFocus} onBlur={onInputBlur} ref={input} {...props} />}</InputWrapper> );};export default Input;
All works perfectly except one thing: If you press on the touchable overlay of the focuses input, you will lose this focus because it triggered the blur
input event.
The question is quite simple then: How to prevent this?
I also tried other ways with the disabled prop of the touchable area or blur event preventing without any luck.
If you also have a better way to handle my need, I'm not against propositions. :-)