diff --git a/index.js b/index.js index cc81d12..be7bf4b 100644 --- a/index.js +++ b/index.js @@ -1,55 +1,90 @@ 'use strict'; -import React, {Component, PropTypes} from 'react'; - -import { - StyleSheet, - TextInput, - LayoutAnimation, - Animated, - Easing, - Text, - View, - Platform -} from 'react-native'; - -var textPropTypes = Text.propTypes || View.propTypes -var textInputPropTypes = TextInput.propTypes || textPropTypes +import createReactClass from 'create-react-class'; +import PropTypes from 'prop-types'; +import React from 'react'; +import { Animated, Easing, Platform, StyleSheet, Text, TextInput, View, ViewPropTypes } from 'react-native'; + +var textPropTypes = Text.propTypes || ViewPropTypes; +var textInputPropTypes = TextInput.propTypes || textPropTypes; var propTypes = { ...textInputPropTypes, inputStyle: textInputPropTypes.style, labelStyle: textPropTypes.style, disabled: PropTypes.bool, - style: View.propTypes.style, -} + isSelectField: PropTypes.bool, + isPercentage: PropTypes.bool, + currency: PropTypes.object, + style: ViewPropTypes.style +}; + +const cleanStyle = { + fontSize: 20, + top: 7 +}; + +const dirtyStyle = { + fontSize: 12, + top: -17 +}; -var FloatingLabel = React.createClass({ +var FloatingLabel = createReactClass({ propTypes: propTypes, - getInitialState () { + getInitialState() { var state = { text: this.props.value, - dirty: (this.props.value || this.props.placeholder) + dirty: Boolean(this.props.value || this.props.placeholder), + focused: Boolean(this.props.autoFocus), + height: 0 }; - var style = state.dirty ? dirtyStyle : cleanStyle + this.cleanStyle = this.props.cleanStyle ? this.props.cleanStyle : cleanStyle; + this.dirtyStyle = this.props.dirtyStyle ? this.props.dirtyStyle : dirtyStyle; + + var style = state.dirty ? this.dirtyStyle : this.cleanStyle; state.labelStyle = { fontSize: new Animated.Value(style.fontSize), top: new Animated.Value(style.top) - } + }; - return state + return state; }, - componentWillReceiveProps (props) { - if (typeof props.value !== 'undefined' && props.value !== this.state.text) { - this.setState({ text: props.value, dirty: !!props.value }) - this._animate(!!props.value) + componentWillReceiveProps(props) { + // if (typeof props.value !== 'undefined' && props.value !== this.state.text) { + // const shouldAnimate = !Boolean(this.state.text); + // this.setState({ text: props.value, dirty: !!Boolean(props.value) }); + // if (props.isSelectField) { + // this._animate(!!props.value); + // } else if (shouldAnimate) { + // this._animate(true); + // } else if (!this.state.focused && !this.state.text) { + // this._animate(false); + // } + // } else if ( + // props.value === undefined && + // (props.keyboardType !== 'numeric' || props.keyboardType !== 'decimal-pad') + // ) { + // this.setState({ text: props.value, dirty: false, focused: false }); + // this._animate(false); + // } + if (props.value !== undefined && props.value !== this.state.text) { + const shouldAnimate = Boolean(props.value); + this.setState({ text: props.value, dirty: !!Boolean(props.value) }); + if (props.isSelectField) { + this._animate(!!props.value); + } else { + this._animate(shouldAnimate || this.state.focused); + } + } else if (props.value === undefined && this.state.text !== '') { + this.setState({ text: props.value, dirty: false }); + this._animate(false); } }, _animate(dirty) { - var nextStyle = dirty ? dirtyStyle : cleanStyle - var labelStyle = this.state.labelStyle + var nextStyle = dirty ? this.dirtyStyle : this.cleanStyle; + var labelStyle = this.state.labelStyle; var anims = Object.keys(nextStyle).map(prop => { return Animated.timing( labelStyle[prop], @@ -58,57 +93,75 @@ var FloatingLabel = React.createClass({ duration: 200 }, Easing.ease - ) - }) + ); + }); - Animated.parallel(anims).start() + Animated.parallel(anims).start(); }, - _onFocus () { - this._animate(true) - this.setState({dirty: true}) + _onFocus() { + this._animate(true); + this.setState({ dirty: true, focused: true }); if (this.props.onFocus) { this.props.onFocus(arguments); } }, - _onBlur () { + _onBlur() { if (!this.state.text) { - this._animate(false) - this.setState({dirty: false}); + this._animate(false); + this.setState({ dirty: false }); } + this.setState({ focused: false }); + if (this.props.onBlur) { this.props.onBlur(arguments); } }, onChangeText(text) { - this.setState({ text }) + this.setState({ text }); if (this.props.onChangeText) { - this.props.onChangeText(text) + this.props.onChangeText(text); } }, updateText(event) { - var text = event.nativeEvent.text - this.setState({ text }) + var text = event.nativeEvent.text; + this.setState({ text }); if (this.props.onEndEditing) { - this.props.onEndEditing(event) + this.props.onEndEditing(event); } }, - _renderLabel () { + _renderLabel() { return ( - + {this.props.children} - ) + ); + }, + + _renderTextInputWithRef() { + return ( + { + this.setState({ height: event.nativeEvent.contentSize.height }); + }} + ref={input => this.props.inputRef && this.props.inputRef(input)} + /> + ); + }, + + _renderCurrency() { + return {this.props.currency.symbol}; + }, + + _renderPercentage() { + return %; }, render() { @@ -116,6 +169,7 @@ var FloatingLabel = React.createClass({ autoCapitalize: this.props.autoCapitalize, autoCorrect: this.props.autoCorrect, autoFocus: this.props.autoFocus, + blurOnSubmit: this.props.blurOnSubmit, bufferDelay: this.props.bufferDelay, clearButtonMode: this.props.clearButtonMode, clearTextOnFocus: this.props.clearTextOnFocus, @@ -153,17 +207,56 @@ var FloatingLabel = React.createClass({ elementStyles.push(this.props.style); } + props.style.push({ height: Math.max(35, this.state.height) }); + + const isCurrency = this.props.currency && Boolean(this.props.value); + const isPercentage = this.props.isPercentage && Boolean(this.props.value); + return ( - + + {isCurrency && this._renderCurrency()} + {isPercentage && this._renderPercentage()} {this._renderLabel()} - { this.input = r; }} - {...props} - > - + {this.props.inputRef ? ( + this.props.editable ? ( + { + this.setState({ height: event.nativeEvent.contentSize.height }); + }} + ref={input => this.props.inputRef && this.props.inputRef(input)} + /> + ) : ( + + { + this.setState({ height: event.nativeEvent.contentSize.height }); + }} + ref={input => this.props.inputRef && this.props.inputRef(input)} + /> + + ) + ) : this.props.editable ? ( + { + this.setState({ height: event.nativeEvent.contentSize.height }); + }} + /> + ) : ( + + { + this.setState({ height: event.nativeEvent.contentSize.height }); + }} + /> + + )} ); - }, + } }); var labelStyleObj = { @@ -171,10 +264,10 @@ var labelStyleObj = { paddingLeft: 9, color: '#AAA', position: 'absolute' -} +}; if (Platform.OS === 'web') { - labelStyleObj.pointerEvents = 'none' + labelStyleObj.pointerEvents = 'none'; } var styles = StyleSheet.create({ @@ -191,19 +284,9 @@ var styles = StyleSheet.create({ fontSize: 20, borderRadius: 4, paddingLeft: 10, - marginTop: 20, + marginTop: 20 }, label: labelStyleObj -}) - -var cleanStyle = { - fontSize: 20, - top: 7 -} - -var dirtyStyle = { - fontSize: 12, - top: -17, -} +}); module.exports = FloatingLabel;