enriched-text-input 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API_REFERENCE.md +119 -0
- package/CONTRIBUTING.md +33 -0
- package/README.md +58 -48
- package/example/App.tsx +38 -35
- package/example/package.json +3 -2
- package/index.ts +3 -2
- package/package.json +1 -1
- package/src/{RichTextInput.tsx → EnrichedTextInput.tsx} +251 -246
- package/src/Toolbar.tsx +24 -23
- package/src/components/StyledText.tsx +106 -0
- package/src/markdownStyles.ts +12 -0
package/API_REFERENCE.md
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
## Props
|
|
4
|
+
|
|
5
|
+
### `ref`
|
|
6
|
+
|
|
7
|
+
A React ref that lets you call any ref methods on the input.
|
|
8
|
+
|
|
9
|
+
### `patterns`
|
|
10
|
+
|
|
11
|
+
An array of style patterns for the input. Use this prop to define which styles should be available for the input to use.
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
interface Pattern {
|
|
15
|
+
name: string;
|
|
16
|
+
render: React.Component;
|
|
17
|
+
opening: string | null;
|
|
18
|
+
closing: string | null;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
A pattern can have either both opening and closing enclosures defined or just the opening enclosure, but cannot have only the closing enclosure defined.
|
|
23
|
+
|
|
24
|
+
### `defaultValue`
|
|
25
|
+
|
|
26
|
+
Provides an initial value for the input. Can be a string or an array of tokens. If it’s a string and it matches any style defined in the `patterns` prop, proper styles will be applied.
|
|
27
|
+
|
|
28
|
+
### `onSelectionChange`
|
|
29
|
+
|
|
30
|
+
Callback that is called when the text input selection is changed.
|
|
31
|
+
|
|
32
|
+
### `onValueChange`
|
|
33
|
+
|
|
34
|
+
Callback that is called when the text input's value changes. You can use this callback to call ref methods such as `.getRawValue()`, `.getRichTextValue()` or `.getTokenizedValue()` to get the text input’s value in your preferred
|
|
35
|
+
|
|
36
|
+
### `onDebounceValueChange`
|
|
37
|
+
|
|
38
|
+
Same as `onValueChange` but with an applied debouncing effect.
|
|
39
|
+
|
|
40
|
+
## Ref methods
|
|
41
|
+
|
|
42
|
+
### `.setValue()`
|
|
43
|
+
|
|
44
|
+
```jsx
|
|
45
|
+
setValue: (value: string | Tokens[]) => void;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Sets the value of the input.
|
|
49
|
+
|
|
50
|
+
- `value: string | Tokens[]` - the value to set the input. If it’s a valid rich text string, the corresponding styling will be applied.
|
|
51
|
+
|
|
52
|
+
### `.setSelection()`
|
|
53
|
+
|
|
54
|
+
```jsx
|
|
55
|
+
setSelection: (start: number, end: number) => void;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Sets the selection of the input.
|
|
59
|
+
|
|
60
|
+
- `start: number` - the start index of the input’s selection.
|
|
61
|
+
- `end: number` - the end index of the input’s selection.
|
|
62
|
+
|
|
63
|
+
### `.focus()`
|
|
64
|
+
|
|
65
|
+
```jsx
|
|
66
|
+
focus: () => void;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Focuses the input;
|
|
70
|
+
|
|
71
|
+
### `.blur()`
|
|
72
|
+
|
|
73
|
+
```jsx
|
|
74
|
+
blur: () => void;
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Blurs the input.
|
|
78
|
+
|
|
79
|
+
### `.toggleStyle()`
|
|
80
|
+
|
|
81
|
+
```jsx
|
|
82
|
+
toggleStyle: (style: string) => void;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Toggles a style at the cursor’s position.
|
|
86
|
+
|
|
87
|
+
- `style: string` - the name of a pattern to toggle.
|
|
88
|
+
|
|
89
|
+
### `.getActiveStyle()`
|
|
90
|
+
|
|
91
|
+
```jsx
|
|
92
|
+
getActiveStyle: () => string[] | [];
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Returns the active styles for the current selection.
|
|
96
|
+
|
|
97
|
+
### `.getRawValue()`
|
|
98
|
+
|
|
99
|
+
```jsx
|
|
100
|
+
getRawValue: () => string;
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Returns the input’s value as a raw string without rich text enclosures.
|
|
104
|
+
|
|
105
|
+
### `.getRichTextValue()`
|
|
106
|
+
|
|
107
|
+
```jsx
|
|
108
|
+
getRichTextValue: () => string;
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Returns the text input’s value as a rich text string matching the patterns for each style defined in the patterns prop. If a style does not define an opening and closing char, it is ignored.
|
|
112
|
+
|
|
113
|
+
### `.getTokenizedValue()`
|
|
114
|
+
|
|
115
|
+
```jsx
|
|
116
|
+
getTokenizedValue: () => Tokens[];
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Returns the text input's value as an array of tokens.
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
## Clone this repo
|
|
4
|
+
|
|
5
|
+
1. Fork and clone your Github froked repo:
|
|
6
|
+
```
|
|
7
|
+
git clone https://github.com/<github_username>/enriched-text-input.git
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
2. Go to cloned repo directory:
|
|
11
|
+
```
|
|
12
|
+
cd enriched-text-input
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Install dependencies
|
|
16
|
+
|
|
17
|
+
1. Install the dependencies in the root of the repo:
|
|
18
|
+
```
|
|
19
|
+
npm install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
2. Go to the example project and install dependencies:
|
|
23
|
+
```
|
|
24
|
+
cd example && npm install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
3. After that you can start the project with:
|
|
28
|
+
```
|
|
29
|
+
cd example && npm start
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Create a pull request
|
|
33
|
+
After making any changes, open a pull request. Once you submit your pull request, it will get reviewed.
|
package/README.md
CHANGED
|
@@ -1,52 +1,36 @@
|
|
|
1
|
-
[](https://discord.gg/DRmNp34bFE)
|
|
2
|
-
|
|
3
1
|
# enriched-text-input
|
|
4
2
|
|
|
5
3
|
> [!Note]
|
|
6
|
-
|
|
4
|
+
This library is still a work in progress. Expect breaking changes.
|
|
5
|
+
>
|
|
7
6
|
|
|
8
|
-
Proof of concept for a JavaScript only rich-text TextInput component for React Native.
|
|
9
|
-
The main idea is to render `<Text>` views as children of `<TextInput>`.
|
|
10
|
-
It will only support text styling since it's not possible to render images inside `Text` views in React Native. [Try it on Expo Snack](https://snack.expo.dev/@patosala/enriched-text-input).
|
|
7
|
+
Proof of concept for a JavaScript only rich-text TextInput component for React Native. The main idea is to render `<Text>` views as children of `<TextInput>`. It will only support text styling since it's not possible to render images inside `Text` views in React Native. [Try it on Expo Snack](https://snack.expo.dev/@patosala/enriched-text-input).
|
|
11
8
|
|
|
12
9
|
## Motivation
|
|
13
|
-
The field for rich-text in react native is still a bit green. Current libraries that add support for rich-text in react native applications are either WebViews wrapping libraries for the web, limiting customization, or require native code which drops support for Expo Go and react-native-web.
|
|
14
|
-
|
|
15
|
-
In theory, by only using JavaScript we are able to provide better cross-platform compatibility and the possibility to style elements however you want as long as they follow react-native's `Text` supported styles.
|
|
16
|
-
|
|
17
|
-
## Features
|
|
18
10
|
|
|
19
|
-
-
|
|
20
|
-
- [x] Rich text format parsing.
|
|
21
|
-
- [ ] Links and mentions.
|
|
22
|
-
- [ ] Custom styling.
|
|
23
|
-
- [ ] Custom rich text patterns.
|
|
24
|
-
- [ ] Exposed event handlers (onSubmit, onChange, onBlur, onFocus, etc).
|
|
25
|
-
- [ ] Custom methods and event handlers (setValue, onStartMention, onStyleChange, etc).
|
|
26
|
-
- [ ] Headings.
|
|
11
|
+
The field for rich-text in react native is still a bit green. Current libraries that add support for rich-text in react native applications are either WebViews wrapping libraries for the web, limiting customization, or require native code which drops support for Expo Go and react-native-web.
|
|
27
12
|
|
|
28
|
-
|
|
29
|
-
- Inline images.
|
|
30
|
-
- Only `Text`component styles are supported.
|
|
13
|
+
In theory, by only using JavaScript we are able to provide better cross-platform compatibility and the possibility to style elements however you want as long as they follow react-native's `Text` supported styles.
|
|
31
14
|
|
|
32
15
|
## Installation
|
|
33
|
-
|
|
16
|
+
|
|
17
|
+
```bash
|
|
34
18
|
npm install enriched-text-input
|
|
35
19
|
```
|
|
36
20
|
|
|
37
21
|
## Usage
|
|
38
|
-
|
|
22
|
+
|
|
23
|
+
```jsx
|
|
39
24
|
import { useRef } from 'react';
|
|
40
25
|
import { StyleSheet, View } from 'react-native';
|
|
41
|
-
|
|
42
|
-
import { RichTextInput, Toolbar } from 'enriched-text-input';
|
|
26
|
+
import { EnrichedTextInput, Toolbar } from 'enriched-text-input';
|
|
43
27
|
|
|
44
28
|
export default function App() {
|
|
45
29
|
const richTextInputRef = useRef(null);
|
|
46
30
|
|
|
47
31
|
return (
|
|
48
32
|
<View style={styles.container}>
|
|
49
|
-
<
|
|
33
|
+
<EnrichedTextInput ref={richTextInputRef}/>
|
|
50
34
|
<Toolbar richTextInputRef={richTextInputRef}>
|
|
51
35
|
<Toolbar.Bold />
|
|
52
36
|
<Toolbar.Italic />
|
|
@@ -66,35 +50,61 @@ const styles = StyleSheet.create({
|
|
|
66
50
|
paddingTop: 120
|
|
67
51
|
},
|
|
68
52
|
});
|
|
53
|
+
```
|
|
69
54
|
|
|
55
|
+
## Current state
|
|
70
56
|
|
|
71
|
-
|
|
57
|
+
At the moment [1/1/2026] `enriched-text-input` works great for things such as small rich-text inputs (Eg. an input for a messaging app with rich-text support) but not for creating whole rich-text editors. This is because inline styles that do not break line are working as expected (Eg. bold, italic or underline work great but styles such as headings break line so they are currently not yet supported).
|
|
72
58
|
|
|
73
|
-
|
|
59
|
+
Live parsing of rich text symbols (such as wrapping words in asterisks `*`) is still a work in progress an not working correctly but you can toggle styles through the ref api of the `EnrichedTextInput` (or use the provided `Toolbar`component as shown in the example usage).
|
|
74
60
|
|
|
75
|
-
|
|
61
|
+
## Features
|
|
76
62
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
63
|
+
- [x] Inline markdown styles (**bold**, *italic*, underline, ~~strikethrough~~ and `inline code`).
|
|
64
|
+
- [ ] Paragraph styles (headings, lists, quotes, etc).
|
|
65
|
+
- [ ] Live rich-text parsing.
|
|
66
|
+
- [ ] Links and mentions.
|
|
67
|
+
- [x] Custom inline styles.
|
|
68
|
+
- [x] Custom methods and event handlers (setValue, onStartMention, onStyleChange, etc).
|
|
81
69
|
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
cd react-native-rich-text
|
|
85
|
-
```
|
|
70
|
+
## API Reference
|
|
86
71
|
|
|
87
|
-
|
|
72
|
+
[API Reference](https://github.com/PatoSala/enriched-text-input/blob/main/API_REFERENCE.md)
|
|
88
73
|
|
|
89
|
-
|
|
90
|
-
```
|
|
91
|
-
npm install
|
|
92
|
-
```
|
|
74
|
+
## Style patterns
|
|
93
75
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
76
|
+
Style patterns are the styles that you provide the input with for it to know how it should display certain portions of the text. You can check their structure in the [API reference](https://github.com/PatoSala/enriched-text-input/blob/main/API_REFERENCE.md#stylePatterns).
|
|
77
|
+
|
|
78
|
+
By default `enriched-text-input` uses a set of markdown styles (such as **bold**, *italic*, underline, ~~strikethrough~~ and `inline code`) for you to use out of the box, but you can provide your own custom styles through the `stylePatterns` prop. Keep in mind that when using this prop `enriched-text-input` will ignore any default style patterns so that only the ones you provided will be valid.
|
|
79
|
+
|
|
80
|
+
If you want you can provide `enriched-text-input` with both default style patterns and any additional style patterns you define:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
import { EnrichedTextInput, markdownStyles } from "enriched-text-input";
|
|
84
|
+
|
|
85
|
+
const customStyles = [
|
|
86
|
+
{
|
|
87
|
+
name: "comment",
|
|
88
|
+
opening: null,
|
|
89
|
+
closing: null,
|
|
90
|
+
render: Comment
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
<EnrichedTextInput
|
|
95
|
+
stylePattrns={[...markdownStyles, ...customStyles]}
|
|
96
|
+
/>
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
##
|
|
100
|
-
|
|
99
|
+
## Applying styles
|
|
100
|
+
|
|
101
|
+
To apply styles you can either toggle them using the `ref` method `.toggleStyle()` which accepts as a parameter the name of a style pattern, or you can use rich-text enclosures while typing. This enclosures are defined within the `stylePatterns` prop and corresponding styles will get applied when a matching pattern is found inside the input.
|
|
102
|
+
|
|
103
|
+
## Known limitations
|
|
104
|
+
|
|
105
|
+
- Inline images.
|
|
106
|
+
- Only `Text` component styles are supported.
|
|
107
|
+
|
|
108
|
+
## Contributing
|
|
109
|
+
|
|
110
|
+
[Contributing guide](https://github.com/PatoSala/enriched-text-input/blob/main/CONTRIBUTING.md)
|
package/example/App.tsx
CHANGED
|
@@ -1,70 +1,73 @@
|
|
|
1
1
|
import { useRef, useState } from 'react';
|
|
2
|
-
import { StyleSheet, View, KeyboardAvoidingView, Text,
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
function Comment({ children }) {
|
|
7
|
-
return (
|
|
8
|
-
<Text style={{
|
|
9
|
-
backgroundColor: "rgba(255, 203, 0, .12)",
|
|
10
|
-
textDecorationLine: "underline",
|
|
11
|
-
textDecorationColor: "rgba(255, 203, 0, .35)",
|
|
12
|
-
}}>
|
|
13
|
-
{children}
|
|
14
|
-
</Text>
|
|
15
|
-
)
|
|
16
|
-
}
|
|
2
|
+
import { StyleSheet, View, KeyboardAvoidingView, Text, Button, TextInput } from 'react-native';
|
|
3
|
+
import { EnrichedTextInput, Toolbar, markdownStyles } from 'enriched-text-input';
|
|
4
|
+
import * as Clipboard from 'expo-clipboard';
|
|
17
5
|
|
|
18
6
|
export default function App() {
|
|
19
7
|
const [rawValue, setRawValue] = useState("");
|
|
8
|
+
const [richTextStringValue, setRichTextStringValue] = useState("");
|
|
9
|
+
const [activeStyles, setActiveStyles] = useState([]);
|
|
10
|
+
console.log("ACTIVE STYLES:", activeStyles);
|
|
20
11
|
const richTextInputRef = useRef(null);
|
|
21
12
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
{ style: "comment", regex: null, render: Comment }
|
|
25
|
-
];
|
|
13
|
+
const handleGetRichText = () => {
|
|
14
|
+
const richText = richTextInputRef.current?.getRichTextValue();
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
richTextInputRef.current?.toggleStyle("comment");
|
|
16
|
+
setRichTextStringValue(richText);
|
|
29
17
|
}
|
|
30
18
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
console.log(richText);
|
|
19
|
+
const handleCopyToClipboard = async (text: string) => {
|
|
20
|
+
await Clipboard.setStringAsync(text);
|
|
34
21
|
}
|
|
35
22
|
|
|
36
23
|
return (
|
|
37
24
|
<KeyboardAvoidingView style={styles.container} behavior="padding">
|
|
38
25
|
<View style={{ flex: 1 }}>
|
|
39
|
-
|
|
26
|
+
<TextInput
|
|
27
|
+
multiline
|
|
40
28
|
style={{ fontSize: 20, padding: 16 }}
|
|
41
29
|
value={rawValue}
|
|
42
30
|
onChangeText={(text) => setRawValue(text)}
|
|
31
|
+
placeholder='Raw text'
|
|
43
32
|
/>
|
|
44
33
|
<Button
|
|
45
34
|
title='Set rich text string'
|
|
46
35
|
onPress={() => richTextInputRef.current?.setValue(rawValue)}
|
|
47
|
-
/>
|
|
48
|
-
|
|
36
|
+
/>
|
|
37
|
+
|
|
38
|
+
<EnrichedTextInput
|
|
49
39
|
ref={richTextInputRef}
|
|
50
|
-
|
|
40
|
+
placeholder="Rich text"
|
|
41
|
+
onValueChange={() => console.log("VALUE CHANGE", richTextInputRef.current?.getRichTextValue())}
|
|
42
|
+
multiline={true}
|
|
43
|
+
/>
|
|
44
|
+
<Button
|
|
45
|
+
title='Get rich text string'
|
|
46
|
+
onPress={handleGetRichText}
|
|
47
|
+
/>
|
|
48
|
+
<Text style={{ padding: 16, fontSize: 20, color: richTextStringValue ? "black" : "#b3b3b3" }}>{richTextStringValue ? richTextStringValue : "Get rich text output will appear here!"}</Text>
|
|
51
49
|
|
|
50
|
+
<View style={{ flexDirection: "row", justifyContent: "center"}}>
|
|
51
|
+
<Button
|
|
52
|
+
title='Clear'
|
|
53
|
+
onPress={() => setRichTextStringValue("")}
|
|
54
|
+
/>
|
|
52
55
|
<Button
|
|
53
|
-
title='
|
|
54
|
-
onPress={
|
|
55
|
-
|
|
56
|
+
title='Copy'
|
|
57
|
+
onPress={() => handleCopyToClipboard(richTextStringValue)}
|
|
58
|
+
/>
|
|
59
|
+
</View>
|
|
56
60
|
</View>
|
|
57
61
|
<View style={{ alignSelf: "end"}}>
|
|
58
62
|
<Toolbar richTextInputRef={richTextInputRef}>
|
|
59
|
-
<Toolbar.Bold
|
|
63
|
+
<Toolbar.Bold/>
|
|
60
64
|
<Toolbar.Italic />
|
|
61
65
|
<Toolbar.Underline />
|
|
62
66
|
<Toolbar.Strikethrough />
|
|
63
67
|
<Toolbar.Code />
|
|
64
|
-
<TouchableOpacity style={styles.toolbarButton} onPress={handleComment}>
|
|
68
|
+
{/* <TouchableOpacity style={styles.toolbarButton} onPress={handleComment}>
|
|
65
69
|
<FontAwesome6 name="comment-alt" size={16} color="black" />
|
|
66
|
-
</TouchableOpacity>
|
|
67
|
-
|
|
70
|
+
</TouchableOpacity> */}
|
|
68
71
|
<Toolbar.Keyboard />
|
|
69
72
|
</Toolbar>
|
|
70
73
|
</View>
|
package/example/package.json
CHANGED
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@expo/vector-icons": "^15.0.3",
|
|
13
|
+
"enriched-text-input": "file:../",
|
|
13
14
|
"expo": "~54.0.25",
|
|
15
|
+
"expo-clipboard": "~8.0.8",
|
|
14
16
|
"expo-status-bar": "~3.0.8",
|
|
15
17
|
"react": "19.1.0",
|
|
16
|
-
"react-native": "0.81.5"
|
|
17
|
-
"enriched-text-input": "file:../"
|
|
18
|
+
"react-native": "0.81.5"
|
|
18
19
|
},
|
|
19
20
|
"private": true,
|
|
20
21
|
"devDependencies": {
|
package/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import EnrichedTextInput from "./src/EnrichedTextInput";
|
|
2
|
+
import { markdownStyles } from "./src/markdownStyles";
|
|
2
3
|
import Toolbar from "./src/Toolbar";
|
|
3
4
|
|
|
4
|
-
export {
|
|
5
|
+
export { EnrichedTextInput, markdownStyles, Toolbar };
|