-
-
Save scf4/012e9f615f6b43a1712a083b162afd94 to your computer and use it in GitHub Desktop.
import React from 'react'; | |
import { View, Text, TextInput, StyleSheet } from 'react-native'; | |
const styles = StyleSheet.create({ | |
wrapper: { | |
width: '90%', | |
height: 24, | |
position: 'relative', | |
alignSelf: 'center', | |
}, | |
inputWrapper: { | |
position: 'absolute', | |
top: 0, | |
height: 24, | |
width: '100%', | |
borderWidth: 1, | |
borderColor: 'gray', | |
}, | |
input: { | |
height: 24, | |
fontSize: 18, | |
width: '100%', | |
}, | |
text: { | |
height: 24, | |
fontSize: 18, | |
position: 'absolute', | |
top: 0, | |
color: 'transparent', | |
}, | |
mention: { | |
backgroundColor: 'rgba(0, 150, 255, .5)', | |
} | |
}); | |
export default class App extends React.Component { | |
state = { | |
inputText: '', | |
formattedText: '', | |
} | |
handleChangeText = (inputText) => { | |
const words = inputText.split(' '); | |
const formattedText = []; | |
words.forEach(word => { | |
if (!word.startsWith('@')) return formattedText.push(word, ' '); | |
const mention = ( | |
<Text key={word} style={styles.mention}> | |
{word} | |
</Text> | |
); | |
formattedText.push(mention, ' '); | |
}); | |
this.setState({ inputText, formattedText }); | |
} | |
render() { | |
return ( | |
<View style={{ marginTop: 48 }}> | |
<View style={styles.wrapper}> | |
<Text style={styles.text}> | |
{this.state.formattedText} | |
</Text> | |
<View style={styles.inputWrapper}> | |
<TextInput | |
style={styles.input} | |
value={this.state.inputText} | |
onChangeText={this.handleChangeText} | |
/> | |
</View> | |
</View> | |
</View> | |
); | |
} | |
} |
Lovely! here's an update I made that worked best for me setup.
What I wanted: A TextInput
that highlights mentions and hashtags .
Note: If want your "Display" and "Input Area" as separate entities, the 2 snippets above will work, but if you want some sort of a rich text editor that highlights as you type the guide below might help.
- Wrap your
TextInput
around aText
component - Remove the
value
props from theTextInput
- Add an
onChangeText
prop that calls yourhandleChangeText
.
const handleChangeText = (inputText) => {
const retLines = inputText.split("\n");
const formattedText = [];
retLines.forEach((retLine) => {
const words = retLine.split(" ");
const contentLength = words.length;
var format = /[ !#@$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\n]/;
words.forEach((word,index) => {
if (
(word.startsWith("@") && !format.test(word.substr(1))) ||
(word.startsWith("#") && !format.test(word.substr(1)))
) {
const mention = (
<Text key={index} style={styles.mention}>
{word}
</Text>
);
if (index !== contentLength - 1) formattedText.push(mention, " ");
else formattedText.push(mention);
} else {
if (index !== contentLength - 1) return formattedText.push(word, " ");
else return formattedText.push(word);
}
});
});
setContent(inputText);// still update your raw text, this will probably go to your api
setFormattedContent(formattedText);
};
//--------render------------
<TextInput
style={styles.input}
onChangeText={handleChangeText}
>
<Text>{formattedContent}</Text>
</TextInput>
@comphonia really cool. I’m looking for something like this that’s production ready. I wonder if there are existing libraries or perhaps we could make one?
Lovely! here's an update I made that worked best for me setup.
What I wanted: A
TextInput
that highlights mentions and hashtags .Note: If want your "Display" and "Input Area" as separate entities, the original code will work, but if you want some sort of a rich text editor that highlights as you type the guide below might help.
- Wrap your
TextInput
around aText
component- Remove the
value
props from theTextInput
- Add an
onChangeText
prop that calls yourhandleChangeText
.const handleChangeText = (inputText) => { const words = inputText.split(" "); const contentLength = words.length; const formattedText = []; words.forEach((word, index) => { if (!word.startsWith("@") && !word.startsWith("#")) { if (index !== contentLength - 1) return formattedText.push(word, " "); else return formattedText.push(word); } const mention = ( <Text key={index} style={styles.mention}> {word} </Text> ); if (index !== contentLength - 1) formattedText.push(mention, " "); else formattedText.push(mention); }); setContent(inputText); // still update your raw text, this will probably go to your api setFormattedContent(formattedText); }; //--------render------------ <TextInput style={styles.input} onChangeText={handleChangeText} > <Text>{formattedContent}</Text> </TextInput>
@scf4 Not really, I think most build their own stuff with react native. I saw this(https://github.com/harshq/react-native-mentions), but it's not so modular.
We can definitely make one!
Your snippet was very helpful for syntax highlighting.
@scf4 Not really, I think most build their own stuff with react native. I saw this(https://github.com/harshq/react-native-mentions), but it's not so modular.
We can definitely make one!
Your snippet was very helpful for syntax highlighting.
Can you show me your code this feature? I had a issue when code syntax highlighting. When user comeback hashtag or mention before, I can't detect it to show list recommend. And it only defined hashtag when had space before (#hashtag#hashtag2 can't defined)
Lovely! here's an update I made that worked best for me setup.
What I wanted: A
TextInput
that highlights mentions and hashtags .Note: If want your "Display" and "Input Area" as separate entities, the 2 snippets above will work, but if you want some sort of a rich text editor that highlights as you type the guide below might help.
- Wrap your
TextInput
around aText
component- Remove the
value
props from theTextInput
- Add an
onChangeText
prop that calls yourhandleChangeText
.const handleChangeText = (inputText) => { const retLines = inputText.split("\n"); const formattedText = []; retLines.forEach((retLine) => { const words = retLine.split(" "); const contentLength = words.length; var format = /[ !#@$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\n]/; words.forEach((word,index) => { if ( (word.startsWith("@") && !format.test(word.substr(1))) || (word.startsWith("#") && !format.test(word.substr(1))) ) { const mention = ( <Text key={index} style={styles.mention}> {word} </Text> ); if (index !== contentLength - 1) formattedText.push(mention, " "); else formattedText.push(mention); } else { if (index !== contentLength - 1) return formattedText.push(word, " "); else return formattedText.push(word); } }); }); setContent(inputText);// still update your raw text, this will probably go to your api setFormattedContent(formattedText); }; //--------render------------ <TextInput style={styles.input} onChangeText={handleChangeText} > <Text>{formattedContent}</Text> </TextInput>
seem if you not set value for text input, selection on IOS not work. Do you have any idea on IOS
super cool! thanks
Hi @comphonia, Can you please show me the code for https://gist.github.com/scf4/012e9f615f6b43a1712a083b162afd94#gistcomment-3426070 ? Was facing some issues
This works great but I'm seeing some unexpected behavior on my end.
I have "mention" color set to red, and all other text set to green. You'll notice in the GIF that after I move the cursor back to the highlighted portion of the code, then press space and start typing again, each letter from then on is very briefly colored red then flips to green. It's very subtle, and only appears to happen if I move the cursor back to a highlighted word and start typing from there.
I'm digging into it to see if I can figure out what's going on, but figured I'd comment here in case anyone has any ideas.
This is a fresh react native project created via expo init
. The entirety of the project is pasted below:
package.json
{
"name": "reactnativeplayground",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "expo start --dev-client",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web"
},
"dependencies": {
"expo": "~44.0.2",
"expo-splash-screen": "~0.14.1",
"expo-status-bar": "~1.2.0",
"react": "17.0.1",
"react-dom": "17.0.1",
"react-native": "0.64.3",
"react-native-web": "0.17.1"
},
"devDependencies": {
"@babel/core": "^7.12.9"
},
"private": true
}
App.js
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View, TextInput } from 'react-native';
export default function App() {
const [testContent, setTestContent] = React.useState('');
const [testFormattedContent, setTestFormattedContent] = React.useState('');
const handleChangeText = (inputText) => {
const retLines = inputText.split("\n");
const formattedText = [];
retLines.forEach((retLine) => {
const words = retLine.split(" ");
const contentLength = words.length;
var format = /[ !#@$%^&*()_+\-=\[\]{};':"\\|,.<>\/?\n]/;
words.forEach((word,index) => {
if (
(word.startsWith("@") && !format.test(word.substr(1))) ||
(word.startsWith("#") && !format.test(word.substr(1)))
) {
const mention = (
<Text key={index} style={{ color: 'red' }}>
{word}
</Text>
);
if (index !== contentLength - 1) formattedText.push(mention, " ");
else formattedText.push(mention);
} else {
if (index !== contentLength - 1) return formattedText.push(word, " ");
else return formattedText.push(word);
}
});
});
setTestContent(inputText);// still update your raw text, this will probably go to your api
setTestFormattedContent(formattedText);
};
return (
<View style={styles.container}>
<TextInput
style={{ flex: 1, margin: 50, borderColor: 'black', borderWidth: 1, color: 'green' }}
onChangeText={handleChangeText}
>
<Text style={{ color: 'green' }}>{testFormattedContent}</Text>
</TextInput>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
// alignItems: 'center',
// justifyContent: 'center',
},
});
<Text key={index} style={{ color: 'red' }}>
{word}
Thank you soooooooo much for this it worked perfectly
@scf4 Not really, I think most build their own stuff with react native. I saw this(https://github.com/harshq/react-native-mentions), but it's not so modular.
We can definitely make one!
Your snippet was very helpful for syntax highlighting.
@comphonia hey man, do you have some source code for what you showed in the gif?
You have to use this for multiline code: