UNPKG

rn-floating-label-input

Version:
213 lines (185 loc) 5.12 kB
'use strict'; import React, {Component} from 'react'; import PropTypes from 'prop-types'; import { StyleSheet, TextInput, LayoutAnimation, Animated, Easing, Text, View, Platform } from 'react-native'; class FloatingLabelInput extends Component { constructor(props) { super(props); const isDirty = (this.props.value || this.props.placeholder); const style = isDirty ? dirtyStyle : cleanStyle; this.state = { text: this.props.value, dirty: isDirty, labelStyle: { fontSize: new Animated.Value(style.fontSize), top: new Animated.Value(style.top) }, }; } componentWillReceiveProps (props) { if (typeof props.value !== 'undefined' && props.value !== this.state.text) { this.setState({ text: props.value, dirty: !!props.value }) this._animate(!!props.value) } } _animate(dirty) { const nextStyle = dirty ? dirtyStyle : cleanStyle const labelStyle = this.state.labelStyle const anims = Object.keys(nextStyle).map(prop => { return Animated.timing( labelStyle[prop], { toValue: nextStyle[prop], duration: 200 }, Easing.ease ) }) Animated.parallel(anims).start() } _onFocus () { this._animate(true) this.setState({dirty: true}) if (this.props.onFocus) { this.props.onFocus(arguments); } } _onBlur () { if (!this.state.text) { this._animate(false) this.setState({dirty: false}); } if (this.props.onBlur) { this.props.onBlur(arguments); } } onChangeText(text) { this.setState({ text }) if (this.props.onChangeText) { this.props.onChangeText(text) } } updateText(event) { const text = event.nativeEvent.text this.setState({ text }) if (this.props.onEndEditing) { this.props.onEndEditing(event) } } _renderLabel () { return ( <Animated.Text ref='label' numberOfLines={this.props.numberOfLines} style={[this.state.labelStyle, styles.label, this.props.labelStyle]} > {this.props.children} </Animated.Text> ) } render() { let props = { autoCapitalize: this.props.autoCapitalize, autoCorrect: this.props.autoCorrect, autoFocus: this.props.autoFocus, bufferDelay: this.props.bufferDelay, clearButtonMode: this.props.clearButtonMode, clearTextOnFocus: this.props.clearTextOnFocus, controlled: this.props.controlled, editable: this.props.editable, enablesReturnKeyAutomatically: this.props.enablesReturnKeyAutomatically, keyboardType: this.props.keyboardType, multiline: this.props.multiline, numberOfLines: this.props.numberOfLines, onBlur: this._onBlur, onChange: this.props.onChange, onChangeText: this.onChangeText, onEndEditing: this.updateText, onFocus: this._onFocus, onSubmitEditing: this.props.onSubmitEditing, password: this.props.secureTextEntry || this.props.password, // Compatibility placeholder: this.props.placeholder, secureTextEntry: this.props.secureTextEntry || this.props.password, // Compatibility returnKeyType: this.props.returnKeyType, selectTextOnFocus: this.props.selectTextOnFocus, selectionState: this.props.selectionState, style: [styles.input], testID: this.props.testID, value: this.state.text, underlineColorAndroid: this.props.underlineColorAndroid, // android TextInput will show the default bottom border onKeyPress: this.props.onKeyPress }, elementStyles = [styles.element]; if (this.props.inputStyle) { props.style.push(this.props.inputStyle); } if (this.props.style) { elementStyles.push(this.props.style); } return ( <View style={elementStyles}> {this._renderLabel()} <TextInput ref={(r) => { this.input = r; }} {...props} > </TextInput> </View> ); } } const textPropTypes = Text.propTypes || View.propTypes; const textInputPropTypes = TextInput.propTypes || textPropTypes; FloatingLabelInput.propTypes = { ...textInputPropTypes, inputStyle: textInputPropTypes.style, labelStyle: textPropTypes.style, disabled: PropTypes.bool, style: View.propTypes.style, }; let labelStyleObj = { marginTop: 21, paddingLeft: 9, color: '#AAA', position: 'absolute' } if (Platform.OS === 'web') { labelStyleObj.pointerEvents = 'none' } const styles = StyleSheet.create({ element: { position: 'relative' }, input: { height: 40, borderColor: 'gray', backgroundColor: 'transparent', justifyContent: 'center', borderWidth: 1, color: 'black', fontSize: 20, borderRadius: 4, paddingLeft: 10, marginTop: 20, }, label: labelStyleObj }) const cleanStyle = { fontSize: 20, top: 7 } const dirtyStyle = { fontSize: 12, top: -17, } export default FloatingLabelInput; module.exports = FloatingLabelInput;