Skip to content

Commit f3b11eb

Browse files
committed
mention-support: Added support for @mentions.
1 parent f32c25b commit f3b11eb

13 files changed

+1085
-95
lines changed

README.md

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,11 @@
22

33
> Visit [original repo](https://github.com/wix/react-native-zss-rich-text-editor) first
44
5-
This resolves [#171](https://github.com/wix/react-native-zss-rich-text-editor/issues/171), [#174](https://github.com/wix/react-native-zss-rich-text-editor/issues/174), and [#178](https://github.com/wix/react-native-zss-rich-text-editor/issues/178)
6-
7-
## Inspirations
8-
9-
For now, the original library has problems of using two deprecated modules, ListView and react-native-webview-bridge-updated. ListView problem is solved by [Ankit-96](https://github.com/Ankit-96) 's [PR](https://github.com/wix/react-native-zss-rich-text-editor/pull/179). So I focused on removing react-native-webview-bridge-updated and making use of react-native-webview.
10-
11-
## What I did
12-
13-
- Did just like what [Ankit-96](https://github.com/Ankit-96) did; replaced ListView with FlatList
14-
- Replaced react-native-webview-bridge-updated with react-native-webview
15-
- Instead of injecting `MessageHandler` into webpage(WebViewBridge) and sending message through `sendToBridge`, I directly inject `zss_editor`'s function calls through `injectJavaScript`. To achieve that, I fixed `WebViewMessageHandler.js` to be mapper function, translating functions of `RichTextEditor` to those of `zss_editor`.
16-
- In `editor.html`, replace `WebViewBridge.send` with `ReactNativeWebView.postMessage`
17-
- Added `./newExample`. You should `$ cd newExample; yarn; cd ios; pod install; cd ..; react-native run-ios;`.
18-
195
## How to use it
206

21-
- `$ yarn add https://github.com/jb-/react-native-zss-rich-text-editor`
22-
- `$ yarn add react-native-webview` (I'm not sure why I have to do this)
23-
- `$ cd ios; pod install;`
24-
25-
## Limitations
26-
27-
- Tested on RN 0.61.5, iOS only.
28-
29-
- Since I worked it for my project only, I did not test it on other versions or on Android platform. If any of you are familiar with both Android and iOS natives, please refer to my project and collaborate.
7+
- `$ yarn add https://github.com/philpettican/react-native-zss-rich-text-editor`
8+
- `$ yarn add react-native-webview`
9+
- `$ cd ios && pod install`
3010

3111
## References
3212

@@ -39,7 +19,10 @@ A fully functional Rich Text Editor for both Android and iOS, based off the [ZSS
3919
## Installation
4020

4121
```
42-
npm i --save react-native-zss-rich-text-editor
22+
npm i --save https://github.com/philpettican/react-native-zss-rich-text-editor
23+
or
24+
yarn add https://github.com/philpettican/react-native-zss-rich-text-editor
25+
cd ios && pod install
4326
```
4427

4528
On Android, add the following to the end of your `android/app/build.gradle`
@@ -51,8 +34,6 @@ project.afterEvaluate {
5134
}
5235
```
5336

54-
Also, follow instructions [here](https://github.com/alinz/react-native-webview-bridge) to add the native `react-native-webview-bridge-updated` dependency.
55-
5637
## Usage
5738

5839
`react-native-zss-rich-text-editor` exports two Components and one const dictionary:
@@ -117,8 +98,8 @@ The editor component. Simply place this component in your view hierarchy to rece
11798
- `alignFull()`
11899
- `insertBulletsList()`
119100
- `insertOrderedList()`
120-
- `insertLink(url, title)`
121-
- `updateLink(url, title)`
101+
- `insertLink(url, title, className)`
102+
- `updateLink(url, title, className)`
122103
- `insertImage(attributes)`
123104
- `setSubscript()`
124105
- `setSuperscript()`
@@ -172,6 +153,14 @@ To know when the title or content are in focus, use the following methods.
172153
- `isTitleFocused()`
173154
- `isContentFocused()`
174155

156+
To start the @mentioning process, use the following method:
157+
158+
- `startMention`
159+
160+
To insert an @mention, first either type an @ character to start the @mentioning process or call the startMention method, then use the following method:
161+
162+
- `insertMention(url, title, className)`
163+
175164
This method registers a function that will get called whenver the cursor position changes or a change is made to the styling of the editor at the cursor's position., The callback will be called with an array of `actions` that are active at the cusor position, allowing a toolbar to respond to changes.
176165

177166
- `registerToolbar(listener)`
@@ -235,13 +224,13 @@ Other props supported by the `RichTextToolbar` component are:
235224

236225
- `actions`
237226

238-
An `array` of `actions` to be provided by this toolbar. The default actions are:
239-
* `actions.insertImage`
240-
* `actions.setBold`
241-
* `actions.setItalic`
242-
* `actions.insertBulletsList`
243-
* `actions.insertOrderedList`
244-
* `actions.insertLink`
227+
An `array` of `actions` to be provided by this toolbar. The default actions are:
228+
_ `actions.insertImage`
229+
_ `actions.setBold`
230+
_ `actions.setItalic`
231+
_ `actions.insertBulletsList`
232+
_ `actions.insertOrderedList`
233+
_ `actions.insertLink`
245234

246235
- `onPressAddLink`
247236
- `onPressAddImage`
@@ -291,6 +280,7 @@ This is a set of consts of all supported actions. These will be passed in arrays
291280
insertHTML: 'INSERT_HTML',
292281
insertCSS: 'INSERT_CSS',
293282
insertExternalCSS: 'INSERT_EXTERNAL_CSS',
283+
startMention: 'START_MENTION',
294284

295285
setBold: 'bold',
296286
setItalic: 'italic',

example/App.js

Lines changed: 75 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,89 @@ import {
66
} from 'react-native-zss-rich-text-editor';
77
import KeyboardSpacer from 'react-native-keyboard-spacer';
88

9-
const HTML = `<a href="https://www.google.com">Google</a>`;
9+
import MentionList from './components/MentionList';
10+
11+
const HTML = `<p> and this is extra HTML</p>`;
1012
const CSS = `
11-
body { background-color: green; }
13+
.my-custom-class { background-color: lightgreen; }
1214
`;
1315
const EXTERNAL_CSS =
1416
'https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css';
1517

1618
export default class RichTextExample extends Component {
19+
state = {
20+
mentionListVisible: false,
21+
mentionSearchText: '',
22+
};
23+
1724
constructor(props) {
1825
super(props);
1926
this.getHTML = this.getHTML.bind(this);
2027
this.setFocusHandlers = this.setFocusHandlers.bind(this);
28+
this.onMentioning = this.onMentioning.bind(this);
29+
this.onFinishMention = this.onFinishMention.bind(this);
30+
this.onListItemPress = this.onListItemPress.bind(this);
31+
}
32+
33+
onMentioning(text) {
34+
this.setState({
35+
mentionListVisible: true,
36+
mentionSearchText: text,
37+
});
38+
}
39+
40+
onFinishMention() {
41+
this.setState({
42+
mentionListVisible: false,
43+
mentionSearchText: '',
44+
});
45+
}
46+
47+
onListItemPress(item, index, items) {
48+
console.log('item', item);
49+
console.log('index', index);
50+
console.log('items', items);
51+
52+
const { name } = item;
53+
this.richtext.insertMention(
54+
`https://www.google.com/${index++}`,
55+
name,
56+
'my-custom-class',
57+
);
58+
}
59+
60+
renderMentionList() {
61+
const { mentionListVisible, mentionSearchText } = this.state;
62+
if (!mentionListVisible) {
63+
return null;
64+
}
65+
66+
return (
67+
<MentionList
68+
search={mentionSearchText}
69+
style={{ flex: 1 }}
70+
onItemPress={this.onListItemPress}
71+
/>
72+
);
2173
}
2274

2375
render() {
2476
return (
2577
<View style={styles.container}>
26-
{true && this.renderInsertHTMLTest()}
27-
{true && this.renderInsertCSSTest()}
28-
{true && this.renderInsertExternalCSSTest()}
78+
{false && this.renderInsertHTMLTest()}
79+
{false && this.renderInsertCSSTest()}
80+
{this.renderMentionList()}
2981
<RichTextEditor
3082
ref={r => (this.richtext = r)}
3183
style={styles.richText}
3284
initialTitleHTML={'Title!!'}
33-
initialContentHTML={`Hello <b>World</b> <p>this is a new paragraph</p> <p>this is another new paragraph</p>`}
85+
initialContentHTML={
86+
'Hello <b>World</b> <p>this is a new paragraph</p> <p>this is another new paragraph</p>'
87+
}
3488
editorInitializedCallback={() => this.onEditorInitialized()}
89+
customCSS={CSS}
90+
onMentioning={this.onMentioning}
91+
onFinishMention={this.onFinishMention}
3592
/>
3693
<RichTextToolbar getEditor={() => this.richtext} />
3794
{Platform.OS === 'ios' && <KeyboardSpacer />}
@@ -42,11 +99,22 @@ export default class RichTextExample extends Component {
4299
onEditorInitialized() {
43100
this.setFocusHandlers();
44101
this.getHTML();
102+
this.richtext.insertExternalCSS(EXTERNAL_CSS);
45103
}
46104

47-
async getHTML() {
105+
async getTitleHtml() {
48106
const titleHtml = await this.richtext.getTitleHtml();
107+
return titleHtml;
108+
}
109+
110+
async getContentHtml() {
49111
const contentHtml = await this.richtext.getContentHtml();
112+
return contentHtml;
113+
}
114+
115+
async getHTML() {
116+
const titleHtml = await this.getTitleHtml();
117+
const contentHtml = await this.getContentHtml();
50118
//alert(titleHtml + ' ' + contentHtml)
51119
}
52120

@@ -90,17 +158,6 @@ export default class RichTextExample extends Component {
90158
></Button>
91159
);
92160
}
93-
94-
renderInsertExternalCSSTest() {
95-
return (
96-
<Button
97-
title="Insert External CSS"
98-
onPress={() => {
99-
this.richtext.insertExternalCSS(EXTERNAL_CSS);
100-
}}
101-
></Button>
102-
);
103-
}
104161
}
105162

106163
const styles = StyleSheet.create({

0 commit comments

Comments
 (0)