Home > Software design >  Manipulation TextInput selection
Manipulation TextInput selection

Time:03-19

I'm trying to make a TextInput with a non-standard placeholder, because I need formatting and the normal, built-in TextInput placeholder doesn't work for me.

In order for the user to start writing from the beginning of the line, as with the normal placeholder, I set the cursor at the beginning of selection={TEXT ? null: {start: 0}. When the user types further, the cursor goes back to the beginning and forces the user to write elloH instead of Hello.

I made an example of my code on Snack, the problem will be clearer when running: https://snack.expo.dev/Vv6lNzUCU

How can this be fixed?

CodePudding user response:

I tried to follow your example but couldn't come up with all the things you're doing. So I made a new snack. It necessarily doesn't answer your question, but that is because you haven't elaborated all the reasons behind that.

What this does, is adding a custom placeholder to be seen when there's no text inside TextInput. And when you add some text, the placeholder will disappear.

Since you're trying to display the contents of written content, I made an assumption (sorry) that you're trying to build some kind of RTE kind of solution. Hence, I took your example and added the hook to highlight text content. So, try highlightedKeywords array for that.

Here is the complete solution to be tested: https://snack.expo.dev/@zvona/manipulation-textinput-selection

And here is the code in case Expo loses their snacks:

import React from 'react';
import { StyleSheet, View, TextInput, Text } from 'react-native';

const highlightedKeywords = ['beep', 'boop'];

const App = () => {
  const [inputText, setInputText] = React.useState('');

  const highlightContent = () => {
    const splitText = inputText.split(' ');

    return splitText.map((str) => {
      if (highlightedKeywords.includes(str)) {
        return <Text style={[styles.overlapText, styles.highlightedText]}>{str}</Text>;
      } else {
        return <Text style={styles.overlapText}>{str}</Text>;
      }
    });
  };

  return (
    <View style={styles.container}>
      <View style={styles.inputContainer}>
        <TextInput style={styles.textInput} onChangeText={setInputText} />
        <View style={styles.placeholder}>
          {inputText.length ? (
            <><Text>{highlightContent()}</Text></>
          ) : (
            <>
              <Text>This is my </Text>
              <Text style={{ backgroundColor: 'yellow' }}>Placeholder</Text>
            </>
          )}
        </View>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    justifyContent: 'center',
    padding: 20,
  },

  inputContainer: {
    position: 'relative',
    width: '100%',
    height: 35,
  },

  textInput: {
    zIndex: 2,
    borderColor: '#202020',
    borderWidth: 2,
    height: '100%',
    padding: 5,
    color: 'transparent',
  },

  placeholder: {
    zIndex: 0,
    position: 'absolute',
    display: 'block',
    height: '100%',
    left: 7,
    top: 8,
  },

  overlapText: {
    marginRight: '0.25em',
  },

  highlightedText: {
    backgroundColor: '#6699CC',
    color: '#ffffff',
  },
});

export default App;

CodePudding user response:

I used Samuli Hakoniemi's idea of opacity and zIndex, but I think I simplified the code a bit:

import React from 'react';
import { 
  StyleSheet, 
  View, 
  TextInput, 
  Text
} from 'react-native';

export default function App() {
  const [TEXT, setText] = React.useState(null);

  return (
    <View style={{ marginTop: 100, padding: 20 }}>
      <View>
        <TextInput
          style={{ 
            padding: 5,
            borderWidth: 1,
            zIndex: 1,
          }}
          autoFocus={true}
          onChangeText={(text) => {
            setText(text);
          }}
          value={TEXT}
        />

        <View style={{
          position: 'absolute',
          justifyContent: 'center',
          left: 5,
          height: '100%',
          zIndex: 0,
          opacity: (TEXT) ? 0 : 1,
        }}>
          <Text>
            <Text>My </Text>
            <Text style={{ backgroundColor: 'yellow' }}>Example</Text>
          </Text>
        </View>
      </View>
    </View>
  );
}

Example in Snack: https://snack.expo.dev/mOuNbvxCU

  • Related