-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
848 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
example/ | ||
__tests__/ | ||
.* | ||
components/ | ||
coverage/ | ||
index.android.js | ||
index.ios.js | ||
android/ | ||
ios/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
import React, {Component} from 'react'; | ||
import { | ||
View, | ||
TextInput, | ||
Text, | ||
Animated, | ||
Platform, | ||
TouchableWithoutFeedback | ||
} from 'react-native'; | ||
import Style from './InputStyle'; | ||
|
||
import StyleSheet from 'react-native-stylesheet-xg'; | ||
|
||
/** RichInput | ||
* @example | ||
* <RichInput label="姓名" value="" placeholder="请输入姓名" onChangeText={(text) => {}}}/> | ||
* @props | ||
* @extends TextInput | ||
* label | ||
* tips | ||
* error | ||
*/ | ||
|
||
const ANIMATION_TIME = 300; | ||
// 末尾留余高度 | ||
const PLUS_HEIGHT = StyleSheet.r(20); | ||
// 最小高度,末尾留余高度,防抖动 | ||
const MULTI_MIN_HEIGHT = StyleSheet.r(40) + PLUS_HEIGHT; | ||
// 校正 | ||
const REVISES = { | ||
ios: StyleSheet.r(20), | ||
android: 0 | ||
}; | ||
|
||
class Input extends Component { | ||
|
||
// 构造 | ||
constructor(props) { | ||
super(props); | ||
// 初始状态 | ||
this.state = { | ||
isFocus: false, | ||
multiHeight: MULTI_MIN_HEIGHT + REVISES[Platform.OS], | ||
animatedFactor: new Animated.Value(0.0001) | ||
}; | ||
|
||
this.lineAnimated = { | ||
transform: [ | ||
{scaleX: this.state.animatedFactor} | ||
] | ||
}; | ||
|
||
this.focusInit = false; | ||
|
||
this.renderLabel = this.renderLabel.bind(this); | ||
this.onFocus = this.onFocus.bind(this); | ||
this.onBlur = this.onBlur.bind(this); | ||
this.onChange = this.onChange.bind(this); | ||
this.onPressLabel = this.onPressLabel.bind(this); | ||
this.getContentSize = this.getContentSize.bind(this); | ||
this.onContentSizeChange = this.onContentSizeChange.bind(this); | ||
} | ||
|
||
onFocus() { | ||
const {onFocus} = this.props; | ||
|
||
this.focusInit = true; | ||
this.setState({ | ||
isFocus: true | ||
}); | ||
|
||
Animated.timing( | ||
this.state.animatedFactor, | ||
{ | ||
duration: ANIMATION_TIME, | ||
toValue: 1 | ||
} | ||
).start(); | ||
|
||
if (typeof onFocus === 'function') { | ||
onFocus(); | ||
} | ||
} | ||
|
||
onBlur() { | ||
const {onBlur} = this.props; | ||
|
||
this.setState({ | ||
isFocus: false | ||
}); | ||
|
||
Animated.timing( | ||
this.state.animatedFactor, | ||
{ | ||
duration: ANIMATION_TIME, | ||
toValue: 0.0001 | ||
} | ||
).start(); | ||
|
||
if (typeof onBlur === 'function') { | ||
onBlur(); | ||
} | ||
} | ||
|
||
getContentSize(event) { | ||
if (this.props.multiline) { | ||
const newHeight = Math.max( | ||
MULTI_MIN_HEIGHT, | ||
event.nativeEvent.contentSize.height + PLUS_HEIGHT + REVISES[Platform.OS] | ||
); | ||
|
||
|
||
if (newHeight !== this.state.multiHeight) { | ||
this.setState({multiHeight: newHeight}); | ||
} | ||
} | ||
} | ||
|
||
onChange(event) { | ||
const {onChange} = this.props; | ||
|
||
this.getContentSize(event); | ||
|
||
if (typeof onChange === 'function') { | ||
onChange(event); | ||
} | ||
} | ||
|
||
onContentSizeChange(event) { | ||
const {onContentSizeChange} = this.props; | ||
|
||
this.getContentSize(event); | ||
|
||
if (typeof onContentSizeChange === 'function') { | ||
onContentSizeChange(event); | ||
} | ||
} | ||
|
||
onPressLabel() { | ||
const {editable, readOnly} = this.props; | ||
|
||
if (editable && !readOnly) { | ||
this.input.focus(); | ||
} | ||
} | ||
|
||
renderLabel() { | ||
const {label, labelStyle, multiline, tips, required} = this.props; | ||
const isColumnMode = multiline || !!tips || (label ? label.length > 5 : false); | ||
|
||
if (typeof label === 'undefined') { | ||
return; | ||
} | ||
|
||
return ( | ||
<TouchableWithoutFeedback onPress={this.onPressLabel}> | ||
<View style={[Style.labelCon, isColumnMode && Style.columnModeLabelCon]}> | ||
<Text style={[Style.label, labelStyle]}> | ||
{required && <Text style={[Style.required]}>*</Text>}{label} | ||
</Text> | ||
{!!tips && <Text style={Style.tips}>{tips}</Text>} | ||
</View> | ||
</TouchableWithoutFeedback> | ||
); | ||
} | ||
|
||
render() { | ||
const { | ||
editable, | ||
multiline, | ||
error, | ||
wrapperStyle, | ||
focusStyle, | ||
disabledStyle, | ||
errorStyle, | ||
initJudge, | ||
readOnly, | ||
label, | ||
tips | ||
} = this.props; | ||
const {isFocus} = this.state; | ||
const isColumnMode = multiline || !!tips || (label ? label.length > 5 : false); | ||
|
||
return ( | ||
<View | ||
style={[ | ||
Style.inputCon, wrapperStyle, | ||
isColumnMode && Style.multiInputCon, | ||
isFocus && Style.focus, isFocus && focusStyle, | ||
initJudge && (error && Style.error), initJudge && (error && errorStyle), | ||
!initJudge && (error && this.focusInit && Style.error), !initJudge && (error && errorStyle), | ||
!editable && Style.disabled, !editable && disabledStyle | ||
]} | ||
> | ||
{this.renderLabel()} | ||
<TextInput | ||
placeholderTextColor={'#ccc'} | ||
underlineColorAndroid={'transparent'} | ||
returnKeyType={'done'} | ||
{...this.props} | ||
editable={editable && !readOnly} | ||
ref={input => this.input = input} | ||
style={[ | ||
Style.input, isColumnMode && Style.columnModeInput, | ||
this.props.style, | ||
multiline && Style.multiInput, | ||
multiline && {height: this.state.multiHeight} | ||
]} | ||
onContentSizeChange={this.onContentSizeChange} | ||
onChange={this.onChange} | ||
onFocus={this.onFocus} | ||
onBlur={this.onBlur} | ||
/> | ||
<Animated.View style={[Style.lineBottom, this.lineAnimated]} /> | ||
{error && <View style={[Style.lineBottom, Style.lineError]} />} | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
Input.defaultProps = { | ||
editable: true, | ||
multiline: false, | ||
error: false, | ||
initJudge: true, | ||
readOnly: false | ||
}; | ||
|
||
Input.propTypes = { | ||
...TextInput.propTypes, | ||
label: React.PropTypes.string, | ||
defaultValue: React.PropTypes.string, | ||
editable: React.PropTypes.bool, | ||
multiline: React.PropTypes.bool, | ||
error: React.PropTypes.bool, | ||
required: React.PropTypes.bool, | ||
tips: React.PropTypes.string, | ||
wrapperStyle: React.PropTypes.object, | ||
focusStyle: React.PropTypes.object, | ||
disabledStyle: React.PropTypes.object, | ||
errorStyle: React.PropTypes.object, | ||
labelStyle: React.PropTypes.object, | ||
initJudge: React.PropTypes.bool, | ||
readOnly: React.PropTypes.bool | ||
}; | ||
|
||
|
||
export default Input; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
import StyleSheet from 'react-native-stylesheet-xg'; | ||
|
||
const Style = StyleSheet.create({ | ||
inputCon: { | ||
flexDirection: 'row', | ||
alignItems: 'center', | ||
height: 45, | ||
paddingLeft: 10, | ||
paddingRight: 10, | ||
borderBottomWidth: 1, | ||
borderBottomColor: '#e5e5e5' | ||
}, | ||
multiInputCon: { | ||
height: null, | ||
flexDirection: 'column', | ||
alignSelf: 'stretch' | ||
}, | ||
focus: { | ||
borderColor: '#ff9900' | ||
}, | ||
error: { | ||
borderColor: '#ec5330' | ||
}, | ||
disabled: { | ||
backgroundColor: '#e5e5e5' | ||
}, | ||
input: { | ||
flexGrow: 1, | ||
height: 44, | ||
padding: 0, | ||
color: '#333', | ||
fontSize: 14 | ||
}, | ||
columnModeInput: { | ||
marginTop: -10, | ||
marginBottom: -5, | ||
alignSelf: 'stretch' | ||
}, | ||
multiInput: { | ||
marginBottom: -20, | ||
textAlignVertical: 'top', | ||
alignSelf: 'stretch', | ||
android: { | ||
paddingTop: 8 | ||
}, | ||
ios: { | ||
marginTop: -3, | ||
marginBottom: -28 | ||
} | ||
}, | ||
labelCon: { | ||
flexDirection: 'row', | ||
width: 90, | ||
height: 44, | ||
alignItems: 'center', | ||
justifyContent: 'flex-start' | ||
}, | ||
columnModeLabelCon: { | ||
width: null, | ||
height: 35, | ||
alignSelf: 'stretch' | ||
}, | ||
label: { | ||
fontSize: 14, | ||
color: '#666' | ||
}, | ||
lineBottom: { | ||
position: 'absolute', | ||
height: 2, | ||
bottom: -1, | ||
left: 0, | ||
right: 0, | ||
backgroundColor: '#ff9900' | ||
}, | ||
lineError: { | ||
backgroundColor: '#ec5330' | ||
}, | ||
tips: { | ||
marginTop: 1, | ||
marginLeft: 5, | ||
fontSize: 12, | ||
color: '#06c1ae' | ||
}, | ||
required: { | ||
fontSize: 14, | ||
color: '#ec5330' | ||
} | ||
}); | ||
|
||
export default Style; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
### The react-native-input-xg | ||
* react native Input component for both Android and iOS based on pure JavaScript | ||
|
||
### Main | ||
* This component provide some more functions besides the basic input RN provided | ||
|
||
### Properties | ||
* Besides the basic properties RN provided, we also provide belows: | ||
|
||
![image](https://raw.githubusercontent.com/lulutia/images/master/react-native-components/Screen-Capture-39.gif) | ||
|
||
### Properties | ||
|
||
| Prop | Default | Type | Description | | ||
| :------------ |:---------------:| :---------------:| :-----| | ||
| label | undefined | `string` | Specify the label of the input | | ||
| defaultValue | undefined | `string` | Specify the default value of the input | | ||
| editable | true | `bool` | if you can edit the input| | ||
| multiline | false | `bool` | if the input support the multiline| | ||
| error | false | `bool` | for you to judge if the content is wrong | | ||
| required| false | `bool` | give you an indicate to show this one is a must | | ||
| tips | undefined | `string` | give some more explanation | | ||
| wrapperStyle | - | `style` | Specify the wrapper style | | ||
| focusStyle | - | `style` | Specify the style when focus | | ||
| disabledStyle | - | `style` | Specify the style when disabled| | ||
| errorStyle | - | `style` | Specify the style when there's some error| | ||
| labelStyle | - | `style` | Specify the label style| | ||
| initJudge | true | `bool` | if judge error when init| | ||
| readOnly | false | `bool` | you can only see but can not operate| |
Oops, something went wrong.