Implement @mention in TextInput
Asked Answered
D

1

21

How can I implement @mention in react native's TextInput?

I've tried this react-native-mention but it is not being maintained anymore. There are so many styling issues and callback issues.

What I want is to display custom view inside TextInput. Something like this.

Suggestionlist view

And after tapping on the list I want to display like this:

enter image description here

So far I am able to achieve:

When I type '@' in TextInput user list appear.

enter image description here

And when I tap on user I get username in TextInput

enter image description here

Code:

   renderSuggestionsRow() {
      return this.props.stackUsers.map((item, index) => {
         return (
            <TouchableOpacity key={`index-${index}`} onPress={() => this.onSuggestionTap(item.label)}>
               <View style={styles.suggestionsRowContainer}>
                  <View style={styles.userIconBox}>
                     <Text style={styles.usernameInitials}>{!!item.label && item.label.substring(0, 2).toUpperCase()}</Text>
                  </View>
                  <View style={styles.userDetailsBox}>
                     <Text style={styles.displayNameText}>{item.label}</Text>
                     <Text style={styles.usernameText}>@{item.label}</Text>
                  </View>
               </View>
            </TouchableOpacity>
         )
      });
   }

   onSuggestionTap(username) {
      this.setState({
         comment: this.state.comment.slice(0, this.state.comment.indexOf('@')) + '#'+username,
         active: false
      });
   }

   handleChatText(value) {
      if(value.includes('@')) {
         if(value.match(/@/g).length > 0) {
            this.setState({active: true});
         }
      } else {
         this.setState({active: false});
      }
      this.setState({comment: value});
   }
render() {
      const {comments} = this.state;
      return (
         <View style={styles.container}>
            {
               this.state.active ?
               <View style={{ marginLeft: 20}}>
                  {this.renderSuggestionsRow()}
               </View> : null
            }
            <View style={{ height: 55}}/>
            <View style={styles.inputContainer}>
               <TextInput
                  style={styles.inputChat}
                  onChangeText={(value) => this.handleChatText(value)}
               >
                  {comment}
               </TextInput>

               <TouchableOpacity style={styles.inputIcon} onPress={() => this.addComment()}>
                  <Icon type='FontAwesome' name='send-o' style={{fontSize: 16, color: '#FFF'}}/>
               </TouchableOpacity>
            </View>
         </View>
      );
   }
Douglas answered 15/9, 2018 at 7:5 Comment(4)
you're going to want an Animated.View, use absolute positioning to get it in or below your text box, then in your onKeyPress function on the TextInput to check if the key pressed is an @Haycock
@RobbieMilejczak i am able to achive what you are trying to say.. now my problem is how do i display in TextInputDouglas
Did you find some solution?Archegonium
One solution would be to use github.com/taskrabbit/react-native-parsed-text by this you would be able to achieve that the @username are rendered bold and the user can press on it (you can detect the @username with a regex pattern). Is this already sufficient or do you need to really display a custom view within the text?Browse
B
2

One simple solution would be to use react-native-parsed-text. Here is an example:

Example

import * as React from "react";
import { Text, View, StyleSheet } from 'react-native';
import ParsedText from 'react-native-parsed-text';

const userNameRegEx = new RegExp(/@([\w\d.\-_]+)?/g);
export default class Example extends React.Component {

  handleNamePress = (name) => {
    alert("Pressed username " + name);
  }

  render() {
    return (
      <View style={styles.container}>
        <ParsedText
          style={styles.text}
          parse={
            [
              {pattern: userNameRegEx, style: styles.username, onPress: this.handleNamePress},
            ]
          }
          childrenProps={{allowFontScaling: false}}
        >
          This is  a text with @someone mentioned!
        </ParsedText>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  text: {
    color: 'black',
    fontSize: 15,
  },
  username: {
    color: 'white',
    fontWeight: 'bold',
    backgroundColor: "purple",
    paddingHorizontal: 4,
    paddingBottom: 2,
    borderRadius: 4,
  },
});

However, this library doesn't support rendering custom views. The example above is achieved by just pure styling. If you need a custom view you need to implement something yourself. For a long time, it wasn't possible to render arbitrary components embedded inside a text-components. However, this has changed now afaik and we can do stuff like this:

<Text>Hello I am an example <View style={{ height: 25, width: 25, backgroundColor: "blue"}}></View> with an arbitrary view!</Text>

Example 2

Check both code examples here: https://snack.expo.io/@hannojg/restless-salsa

One important note: You can render the output of the ParsedText or your own custom component inside the TextInput, like this:

<TextInput
 ...
>
  <ParsedText
   ...
  >
    {inputValue}
  </ParsedText>
</TextInput>
Browse answered 31/12, 2020 at 10:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.