From 9ed94276dc9e9eaf661c60ab67fc1f4d94781269 Mon Sep 17 00:00:00 2001 From: Hunkyo Jung Date: Wed, 3 Aug 2016 22:40:45 +0900 Subject: [PATCH 1/4] Update Readme.md Update Readme.md --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9fbe07b..697196c 100644 --- a/README.md +++ b/README.md @@ -1 +1,56 @@ -# react-native-taginput \ No newline at end of file + +## react-native-taginput +[![npm version](https://badge.fury.io/js/react-native-scrollable-tab-view.svg)](https://badge.fury.io/js/react-native-scrollable-tab-view) + +This is probably my favorite navigation pattern on Android, I wish it +were more common on iOS! This is a very simple JavaScript-only +implementation of it for React Native. For more information about how +the animations behind this work, check out the Rebound section of the +[React Native Animation Guide](https://facebook.github.io/react-native/docs/animations.html) + + +## Add it to your project + +1. Run `npm install react-native-taginput --save` +2. `import TagInput from 'react-native-taginput` + +## Basic usage + +```javascript +var ScrollableTabView = require('react-native-scrollable-tab-view'); + +var App = React.createClass({ + render() { + return ( + + + + + + ); + } +}); +``` + +## Examples + +> Add example link + +## Props + +> Add props + +## Contribution +**Issues** are welcome. Please add a screenshot of bug and code snippet. + +**Pull requests** are welcome. If you want to change API or making something big better to create issue and discuss it first. Before submiting PR please run ```eslint .``` Also all eslint fixes are welcome. + +Please attach video or gif to PR's and issues it is super helpful. + +How to make video + +How to make gif from video + +--- + +**MIT Licensed** From 9f0f882f41918f07e95b8a5484f3b34f44d2a178 Mon Sep 17 00:00:00 2001 From: Hunkyo Jung Date: Mon, 8 Aug 2016 14:42:45 +0900 Subject: [PATCH 2/4] Apply working code --- Tag.js | 96 +++++++++-------------- index.js | 230 ++++++++++++++++++++++++++++++++++++------------------- 2 files changed, 188 insertions(+), 138 deletions(-) diff --git a/Tag.js b/Tag.js index 551aac7..1088aa2 100644 --- a/Tag.js +++ b/Tag.js @@ -1,68 +1,48 @@ - - -import React, { Component } from 'react'; +import React, { PropTypes } from 'react'; import { StyleSheet, View, Text, - TouchableWithoutFeedback + TouchableHighlight, } from 'react-native'; -class Tag extends Component { - - static propTypes = { - text: React.PropTypes.string.isRequired, - onPress: React.PropTypes.func, - } - - static defaultProps = { - text: 'none', - onPress: () => {}, - } +const Tag = ({ + text, + tagContainer, + onPress, +}) => { + const styles = StyleSheet.create({ + container: { + justifyContent: 'center', + backgroundColor: 'gray', + paddingHorizontal: 5, + margin: 2, + borderRadius: 3, + height:20, + }, + text: { + fontSize: 10, + color: '#ffffff' + }, + }) + + return ( + + {text} + + ); +} - render() { - return ( - - {this.props.text} - this.props.onPress()}> - - X - - - - ) - } +Tag.propTypes = { + text: PropTypes.string, + tagContainer: View.propTypes.style, + onPress: PropTypes.func, } -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - backgroundColor: 'gray', - paddingHorizontal: 5, - margin: 5, - borderRadius: 5, - alignItems: 'center', - height:30, - }, - text: { - fontSize: 16, - color: '#ffffff' - }, - delete: { - justifyContent:'center', - alignItems: 'center', - width: 14, - height: 14, - borderColor: 'white', - borderWidth: 0.5, - borderRadius: 7, - right:0, - marginLeft:5, - }, - deleteText: { - fontSize: 12, - color: '#ffffff' - } -}); +Tag.defaultProps = { + text: 'none', + tagContainer: null, + onPress: () => {}, +} -export default Tag; \ No newline at end of file +export default Tag; diff --git a/index.js b/index.js index 4e5a3d6..ad9aada 100644 --- a/index.js +++ b/index.js @@ -12,16 +12,34 @@ import { import Tag from './Tag'; -class TagInput extends Component { +export default class TagInput extends Component { static propTypes = { initialTags: React.PropTypes.arrayOf(React.PropTypes.string), - tagList: React.PropTypes.arrayOf(React.PropTypes.string), + suggestions: React.PropTypes.arrayOf(React.PropTypes.string), + placeholder: React.PropTypes.string, + footerText: React.PropTypes.string, + height: React.PropTypes.number, + fontSize: React.PropTypes.number, + containerStyle: View.propTypes.style, + inputContainerStyle: View.propTypes.style, + textInputStyle: TextInput.propTypes.style, + listStyle: ListView.propTypes.style, + onUpdateTags: React.PropTypes.func, + onUpdateLayout: React.PropTypes.func, } static defaultProps = { initialTags: [], - tagList: [], + suggestions: [], + placeholder: 'Select tag or enter tag name...', + footerText: 'Add a new tag', + onUpdateTags: () => {}, + onUpdateLayout: () => {}, + containerStyle: null, + inputContainerStyle: null, + textInputStyle: null, + listStyle: null, } constructor(props) { @@ -30,58 +48,89 @@ class TagInput extends Component { var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); this.state = { - dataSource: ds.cloneWithRows(props.tagList), + dataSource: ds.cloneWithRows(this._filterList(props.initialTags)), showlist: false, tags: props.initialTags, + userInput: '', + listPosition: { + top: 0, + left: 0, + right: 0, + } } } - triggerBlur() { - if (this.refs.textInput) this.refs.textInput.blur(); + getTags() { + return this.state.tags; } - _getFilterList(newArray) { + blur() { + this.refs.textInput.blur(); + } - var filteredList = this.props.tagList.filter((tag) => { - var temp = newArray.find((t) => { - return t === tag; - }); - return tag !== temp; - }) + focus() { + this.refs.textInput.focus(); + } + clearText() { + this.setState({userInput: ''}); + this.refs.textInput.setNativeProps({text: ''}); + } + + _filterList(newTags) { + var filteredList = this.props.suggestions.filter((tag) => { + return tag !== newTags.find((t) => (t === tag)) + }); return filteredList; } _addTag(text) { - var newArray = this.state.tags.concat([text]); - var filteredList = this._getFilterList(newArray); + var newTags = this.state.tags.concat([text]); + var filteredList = this._filterList(newTags); this.setState({ - tags: newArray, + tags: newTags, dataSource: this.state.dataSource.cloneWithRows(filteredList) }); + + this.clearText(); + + this.props.onChange(newTags); } _renderRow(rowData, sectionID, rowID) { return ( - + {rowData} ) } + _renderFooter() { + const { userInput, tags } = this.state; + const shouldRender = ( userInput && !tags.includes(userInput) ) ? true : false; + if (shouldRender) { + return ( + + + {this.props.footerText + ' \"' + userInput + '\"'} + + + ) + } + + return null; + } + _renderSeparator(sectionID, rowID, adjacentRowHighlighted) { return ( - + ) } _onBlur() { - this.triggerBlur(); + this.blur(); this.setState({showList: false}); } @@ -89,65 +138,85 @@ class TagInput extends Component { this.setState({showList: true}); } - _onChange(event) { - console.log('onChange'); - } - _onChangeText(text) { - var filteredList = this.props.tagList.filter((tag) => { - return tag.includes(text); + var filteredList = this.props.suggestions.filter((tag) => { + return !this.state.tags.find(t => (t === tag)) && tag.includes(text); }) - this.setState({dataSource: this.state.dataSource.cloneWithRows(filteredList)}); + this.setState({ + dataSource: this.state.dataSource.cloneWithRows(filteredList), + userInput: text, + }); } _getListView() { - if(this.state.showList === true) { - return ( - this._listView = component} - keyboardShouldPersistTaps={true} - keyboardDismissMode="on-drag" - dataSource={this.state.dataSource} - enableEmptySections={true} - renderRow={this._renderRow.bind(this)} - renderSeparator={this._renderSeparator.bind(this)} - /> - ) + const { dataSource, listPosition } = this.state; + const { listStyle } = this.props; + + if(!this.state.showList) { + return null; } - return null; + return ( + + ) } _removeTag(tag) { - console.log(tag); - var newTags = this.state.tags.filter((t) => (t !== tag)); - var filteredList = this._getFilterList(newTags); + var filteredList = this._filterList(newTags); this.setState({ tags: newTags, dataSource: this.state.dataSource.cloneWithRows(filteredList), + }); + + this.props.onChange(newTags); + } + + _onChangeLayout(e) { + let layout = e.nativeEvent.layout; + + this.setState({ + listPosition: { + top: layout.height, + left: 0, + right: 0, + } }) + + this.props.onUpdateLayout(layout); } render() { + + const { placeholder, containerStyle, inputContainerStyle, textInputStyle } = this.props; + return ( - - - - {this.state.tags.map((tag) => ( - - ))} - - + + + {this.state.tags.map((tag) => ( + + ))} + 0 ? '' : this.props.placeholder} + onChangeText={this._onChangeText.bind(this)} + onFocus={this._onFocus.bind(this)} + onBlur={this._onBlur.bind(this)} + autoCorrect={false} + autoCapitalize='none' + /> {this._getListView()} @@ -157,38 +226,39 @@ class TagInput extends Component { const styles = StyleSheet.create({ container: { - backgroundColor: '#F5FCFF', - borderWidth:1, - borderColor: 'gray', + flex: 1, }, - taginputBox: { + inputContainer: { flexDirection:'row', flexWrap: 'wrap', - margin: 5, - padding: 5, + padding: 2, borderColor: 'gray', borderWidth: 1, borderRadius: 5, + minHeight:20, }, textinput: { - flex:1, + flex: 1, + fontSize:10, alignSelf: 'stretch', - fontSize: 16, minWidth: 50, + height:20, + margin:2 }, - taglist: { - height:300, - }, - tagContainer: { - backgroundColor: '#242424', + rowContainer: { + backgroundColor: 'white', justifyContent:'center', - paddingHorizontal: 16, - height: 40, + padding:10, }, text: { - fontSize: 16, - color: 'white', + fontSize: 10, + }, + separator: { + height:1, + alignSelf: 'stretch', + backgroundColor: '#666666', }, + list: { + position: 'absolute', + } }); - -module.exports = TagInput; From 35c641aac8321f8412517e422ff6a85397ed931f Mon Sep 17 00:00:00 2001 From: Hunkyo Jung Date: Mon, 8 Aug 2016 14:54:18 +0900 Subject: [PATCH 3/4] Update Readme.md Update documentation --- README.md | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 697196c..7df6702 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,13 @@ ## react-native-taginput -[![npm version](https://badge.fury.io/js/react-native-scrollable-tab-view.svg)](https://badge.fury.io/js/react-native-scrollable-tab-view) -This is probably my favorite navigation pattern on Android, I wish it -were more common on iOS! This is a very simple JavaScript-only -implementation of it for React Native. For more information about how -the animations behind this work, check out the Rebound section of the -[React Native Animation Guide](https://facebook.github.io/react-native/docs/animations.html) +Tag input component fro React Native +## ChangeLog +- v0.1.0 + - Initial working version -## Add it to your project +## Installation 1. Run `npm install react-native-taginput --save` 2. `import TagInput from 'react-native-taginput` @@ -17,19 +15,24 @@ the animations behind this work, check out the Rebound section of the ## Basic usage ```javascript -var ScrollableTabView = require('react-native-scrollable-tab-view'); +import TagInput from 'react-native-taginput'; -var App = React.createClass({ +class App extends Component { render() { return ( - - - - - + + + ); } -}); +} ``` ## Examples @@ -41,15 +44,10 @@ var App = React.createClass({ > Add props ## Contribution -**Issues** are welcome. Please add a screenshot of bug and code snippet. +**Issues** and **Pull requests** are welcome. Please add a screenshot of bug and code snippet. -**Pull requests** are welcome. If you want to change API or making something big better to create issue and discuss it first. Before submiting PR please run ```eslint .``` Also all eslint fixes are welcome. - -Please attach video or gif to PR's and issues it is super helpful. - -How to make video - -How to make gif from video +## About +This is inspired by [react-native-autocomplete-input](https://github.com/l-urence/react-native-autocomplete-input). --- From 13e7c64732843d5b4311c737a8a8f39667c4441e Mon Sep 17 00:00:00 2001 From: Hunkyo Jung Date: Mon, 8 Aug 2016 14:58:15 +0900 Subject: [PATCH 4/4] Update Readme.md Update properties --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7df6702..54872f2 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,17 @@ class App extends Component { ## Props -> Add props +| Prop | Type | Description | +:------------ |:---------------:| :-----| +| initialTags | array | | +| suggestions | array | | +| containerStyle | style | | +| inputContainerStyle | style | | +| listStyle | style | | +| placeholder | string | | +| onUpdateTags | function | | +| onUpdateLayout | function | | + ## Contribution **Issues** and **Pull requests** are welcome. Please add a screenshot of bug and code snippet.