Skip to content

Instantly share code, notes, and snippets.

@mattiamanzati
Created September 22, 2015 07:19
Show Gist options
  • Save mattiamanzati/3dda55ae4b59cf6b9a5e to your computer and use it in GitHub Desktop.
Save mattiamanzati/3dda55ae4b59cf6b9a5e to your computer and use it in GitHub Desktop.
var React = require('react-native');
var EventEmitter = require('eventemitter3');
var MyTextInput = require('./TextInput');
var {View, Text, TextInput, TouchableOpacity, StyleSheet} = React;
var styles = StyleSheet.create({
wrapper: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0
},
overlay: {
padding: 15,
backgroundColor: 'rgba(0, 0, 0, 0.75)'
},
inputContainer: {
flexDirection: 'row',
backgroundColor: '#FFFFFF',
marginBottom: 10,
alignItems: 'center'
},
input: {
flex: 1,
borderRadius: 2,
padding: 10,
height: 40
},
dismiss: {
fontSize: 20,
lineHeight: 20,
fontWeight: 'bold'
},
dismissButton: {
padding: 10
},
hint: {
textAlign: 'center',
color: '#FFFFFF',
marginBottom: 10
},
results: {
borderRadius: 4,
flex: 1,
backgroundColor: '#FFFFFF'
}
});
class AutoCompleteMediator extends EventEmitter{
constructor(props){
super(props);
}
focus(autoComplete, value){
this.emit('focus', autoComplete, value);
}
attach(overlay){
this.on('focus', overlay.onAutoCompleteFocus);
}
detach(overlay){
this.off('focus', overlay.onAutoCompleteFocus);
}
}
var mediator = new AutoCompleteMediator();
class AutoCompleteOverlay extends React.Component{
constructor(props){
super(props);
// initialize state
this.state = {
value: '',
shown: false,
autoComplete: null
};
// autobinding
this.onChange = this.onChange.bind(this);
this.dismissOverlay = this.dismissOverlay.bind(this);
this.onAutoCompleteFocus = this.onAutoCompleteFocus.bind(this);
}
componentDidMount(){
mediator.attach(this);
}
componentWillUnmount(){
mediator.detach(this);
}
// an autocomplete focused, open the overlay mama!
onAutoCompleteFocus(autoComplete, value){
this.setState({shown: true, autoComplete, value});
}
// handle suggestions
onChange(e){
if(this.state.autoComplete) this.state.autoComplete.onChange(e);
this.setState({value: e.nativeEvent.text});
}
// dismiss the overlay
dismissOverlay(){
if(this.state.autoComplete) this.state.autoComplete.onBlur();
this.setState({shown: false, autoComplete: null});
}
render(){
// deconstruct
var {children, style, ...props} = this.props;
// if not shown, return only the children
//
var overlay = null;
if(this.state.shown){
overlay = <View {...props} style={[styles.wrapper, styles.overlay].concat(Array.isArray(style) ? style : [style])}>
<View style={styles.inputContainer}>
<TextInput underlineColorAndroid="transparent" value={this.state.value} onChange={this.onChange} autoFocus={true} onSubmitEditing={this.dismissOverlay} onEndEditing={this.dismissOverlay} style={styles.input} />
<TouchableOpacity onPress={this.dismissOverlay} style={styles.dismissButton}>
<Text style={styles.dismiss}>×</Text>
</TouchableOpacity>
</View>
{this.state.value ? null : <Text style={styles.hint}>Start typing to see suggestions...</Text>}
{this.state.value && !this.state.pending && !this.state.items ? <Text style={styles.hint}>No suggestion found.</Text> : null}
{this.state.value && !this.state.pending && this.state.items ? <View style={styles.results}></View> : null}
</View>;
}
// render
return <View style={styles.wrapper}>
{children}
{overlay}
</View>;
}
}
class AutoComplete extends React.Component{
constructor(props, ctx){
super(props, ctx);
// handles internally the value
this.state = {};
// autobind
this.onFocus = this.onFocus.bind(this);
this.onChange = this.onChange.bind(this);
this.onBlur = this.onBlur.bind(this);
}
onFocus(e){
// deconstruct
var {onFocus, onChange, onBlur, ...props} = this.props;
// call and focus the overlay
if(onFocus) onFocus(e);
mediator.focus(this, this.state.value);
}
onChange(e){
// deconstruct
var {onFocus, onChange, onBlur, ...props} = this.props;
// handle on change
if(onChange) onChange(e);
// set value
this.setState({value: e.nativeEvent.text});
}
onBlur(e){
// deconstruct
var {onFocus, onChange, onBlur, ...props} = this.props;
// handle on change
if(onBlur) onBlur(e);
}
render(){
// deconstruct
var {onFocus, onChange, onBlur, ...props} = this.props;
// render
return <MyTextInput {...props} onChange={this.onChange} onFocus={this.onFocus} />;
}
}
AutoComplete.Overlay = AutoCompleteOverlay;
module.exports = AutoComplete;
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
} = React;
var AutoComplete = require('./AutoComplete');
var demoerror = React.createClass({
render: function() {
return (
<View style={styles.container}>
<AutoComplete.Overlay>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.android.js
</Text>
<Text style={styles.instructions}>
Shake or press menu button for dev menu
</Text>
<AutoComplete />
</AutoComplete.Overlay>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
AppRegistry.registerComponent('demoerror', () => demoerror);
var React = require('react-native');
var {View, Text, StyleSheet} = React;
var ReactNativeTextInput = React.TextInput;
module.exports = class TextInput extends React.Component{
render(){
// deconstruct
var {style, ...props} = this.props;
// render
return <View style={[styles.main].concat(Array.isArray(style) ? style : [style])}>
<ReactNativeTextInput underlineColorAndroid="transparent" {...props} style={styles.input}/>
</View>;
}
}
let styles = StyleSheet.create({
main: {
borderBottomColor: '#2980b9',
borderBottomWidth: 3,
marginBottom: 3
},
input: {
padding: 5,
height: 30,
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment