Skip to content

Commit 9135497

Browse files
committed
replacing the antique markdown lib with a newer one for fixing some issues
1 parent 2c9b87e commit 9135497

File tree

6 files changed

+184
-85
lines changed

6 files changed

+184
-85
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@
9090
},
9191
"dependencies": {
9292
"@babel/runtime": "7.11.2",
93-
"@stream-io/react-native-simple-markdown": "1.2.1",
9493
"anchorme": "^1.1.2",
9594
"dayjs": "1.9.3",
9695
"file-loader": "6.1.1",
@@ -102,6 +101,7 @@
102101
"react-art": "^16.8.6",
103102
"react-native-actionsheet": "2.4.2",
104103
"react-native-image-zoom-viewer": "3.0.1",
104+
"react-native-markdown-package": "1.8.1",
105105
"seamless-immutable": "7.1.4",
106106
"stream-chat": "2.9.0",
107107
"styled-components": "5.2.0",

src/components/Message/MessageSimple/MessageSimple.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import type {
1717

1818
import type { MessageActionSheetProps } from './MessageActionSheet';
1919
import type { MessageTextProps } from './MessageTextContainer';
20+
import type { MarkdownRules } from './utils/renderText';
2021

2122
import type { ActionProps, MessageProps } from '../Message';
2223

@@ -225,7 +226,7 @@ export type MessageSimpleProps<
225226
/** Boolean if current message is part of thread */
226227
isThreadList?: boolean;
227228
/** Object specifying rules defined within simple-markdown https://github.com/Khan/simple-markdown#adding-a-simple-extension */
228-
markdownRules?: UnknownType;
229+
markdownRules?: MarkdownRules;
229230
/**
230231
* Array of allowed actions on message. e.g. ['edit', 'delete', 'reactions', 'reply']
231232
* If all the actions need to be disabled, empty array or false should be provided as value of prop.

src/components/Message/MessageSimple/MessageTextContainer.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useContext } from 'react';
22

33
import { capitalize } from './utils/capitalize';
4-
import { renderText } from './utils/renderText';
4+
import { MarkdownRules, renderText } from './utils/renderText';
55

66
import { styled, ThemeContext } from '../../../styles/styledComponents';
77

@@ -121,7 +121,7 @@ export type MessageTextContainerProps<
121121
*/
122122
openThread: () => void;
123123
/** Object specifying rules defined within simple-markdown https://github.com/Khan/simple-markdown#adding-a-simple-extension */
124-
markdownRules?: UnknownType;
124+
markdownRules?: MarkdownRules;
125125
/**
126126
* Custom UI component to display a message in MessageList component
127127
* Default component (accepts the same props): [MessageSimple](https://getstream.github.io/stream-chat-react-native/#messagesimple)
@@ -133,6 +133,8 @@ export type MessageTextContainerProps<
133133
MessageText?: React.ComponentType<
134134
MessageTextProps<At, Ch, Co, Ev, Me, Re, Us>
135135
>;
136+
/** Function specifying interaction of links in rendered text */
137+
onLink?: (url: string) => Promise<void>;
136138
};
137139

138140
export const MessageTextContainer = <
@@ -152,6 +154,7 @@ export const MessageTextContainer = <
152154
markdownRules = {},
153155
message,
154156
MessageText,
157+
onLink,
155158
} = props;
156159
const theme = useContext(ThemeContext);
157160

@@ -181,6 +184,7 @@ export const MessageTextContainer = <
181184
markdownRules,
182185
markdownStyles,
183186
message,
187+
onLink,
184188
})
185189
)}
186190
</TextContainer>

src/components/Message/MessageSimple/utils/renderText.tsx

Lines changed: 109 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import React from 'react';
22
import { Linking, Text } from 'react-native';
3-
// @ts-expect-error
4-
import Markdown from '@stream-io/react-native-simple-markdown';
53
import anchorme from 'anchorme';
64
import truncate from 'lodash/truncate';
7-
8-
import type { ReactNodeOutput } from 'simple-markdown';
5+
// @ts-expect-error
6+
import Markdown from 'react-native-markdown-package';
7+
import {
8+
DefaultRules,
9+
defaultRules,
10+
MatchFunction,
11+
ParseFunction,
12+
parseInline,
13+
ReactNodeOutput,
14+
} from 'simple-markdown';
915

1016
import type { MarkdownStyle } from '../../../../styles/themeConstants';
1117
import type { Message } from '../../../MessageList/utils/insertDates';
@@ -20,7 +26,10 @@ import type {
2026
UnknownType,
2127
} from '../../../../types/types';
2228

23-
const defaultMarkdownStyles = {
29+
const defaultMarkdownStyles: MarkdownStyle = {
30+
autolink: {
31+
textDecorationLine: 'underline',
32+
},
2433
inlineCode: {
2534
backgroundColor: '#F3F3F3',
2635
borderColor: '#dddddd',
@@ -29,16 +38,27 @@ const defaultMarkdownStyles = {
2938
padding: 3,
3039
paddingHorizontal: 5,
3140
},
32-
link: {
33-
color: 'blue',
34-
textDecorationLine: 'underline',
41+
// unfortunately marginVertical doesn't override the defaults for these within the 3rd party lib
42+
paragraph: {
43+
marginBottom: 0,
44+
marginTop: 0,
3545
},
36-
url: {
37-
color: 'blue',
38-
textDecorationLine: 'underline',
46+
paragraphCenter: {
47+
marginBottom: 0,
48+
marginTop: 0,
49+
},
50+
paragraphWithImage: {
51+
marginBottom: 0,
52+
marginTop: 0,
3953
},
4054
};
4155

56+
const parse: ParseFunction = (capture, parser, state) => ({
57+
content: parseInline(parser, capture[0], state),
58+
});
59+
60+
export type MarkdownRules = Partial<DefaultRules>;
61+
4262
export type RenderTextParams<
4363
At extends UnknownType = DefaultAttachmentType,
4464
Ch extends UnknownType = DefaultChannelType,
@@ -48,9 +68,10 @@ export type RenderTextParams<
4868
Re extends UnknownType = DefaultReactionType,
4969
Us extends UnknownType = DefaultUserType
5070
> = {
51-
markdownRules: UnknownType;
71+
markdownRules: MarkdownRules;
5272
markdownStyles: MarkdownStyle;
5373
message: Message<At, Ch, Co, Ev, Me, Re, Us>;
74+
onLink?: (url: string) => Promise<void>;
5475
};
5576

5677
export const renderText = <
@@ -64,7 +85,12 @@ export const renderText = <
6485
>(
6586
params: RenderTextParams<At, Ch, Co, Ev, Me, Re, Us>,
6687
) => {
67-
const { markdownRules, markdownStyles, message } = params;
88+
const {
89+
markdownRules,
90+
markdownStyles,
91+
message,
92+
onLink: onLinkParams,
93+
} = params;
6894

6995
// take the @ mentions and turn them into markdown?
7096
// translate links
@@ -86,48 +112,100 @@ export const renderText = <
86112
newText = newText.replace(urlInfo.raw, markdown);
87113
}
88114

89-
if (mentioned_users.length) {
90-
for (let i = 0; i < mentioned_users.length; i++) {
91-
const username = mentioned_users[i].name || mentioned_users[i].id;
92-
const markdown = `**@${username}**`;
93-
const regEx = new RegExp(`@${username}`, 'g');
94-
newText = newText.replace(regEx, markdown);
95-
}
96-
}
97-
98115
newText = newText.replace(/[<&"'>]/g, '\\$&');
99-
const styles = {
116+
const styles: MarkdownStyle = {
100117
...defaultMarkdownStyles,
101118
...markdownStyles,
119+
autolink: {
120+
...defaultMarkdownStyles.autolink,
121+
...markdownStyles?.autolink,
122+
},
123+
inlineCode: {
124+
...defaultMarkdownStyles.inlineCode,
125+
...markdownStyles?.inlineCode,
126+
},
127+
mentions: {
128+
...defaultMarkdownStyles.mentions,
129+
...markdownStyles?.mentions,
130+
},
131+
text: {
132+
...defaultMarkdownStyles.text,
133+
...markdownStyles?.text,
134+
},
102135
};
103136

104137
const onLink = (url: string) =>
105-
Linking.canOpenURL(url).then(
106-
(canOpenUrl) => canOpenUrl && Linking.openURL(url),
107-
);
138+
onLinkParams
139+
? onLinkParams(url)
140+
: Linking.canOpenURL(url).then(
141+
(canOpenUrl) => canOpenUrl && Linking.openURL(url),
142+
);
108143

109144
const react: ReactNodeOutput = (node, output, { ...state }) => {
110-
state.withinText = true;
111-
state.stylesToApply = node.target.match(/@/) ? styles.mailTo : styles.link;
112-
return React.createElement(
145+
state.withinLink = true;
146+
const link = React.createElement(
113147
Text,
114148
{
115149
key: state.key,
116150
onPress: () => onLink(node.target),
117-
style: state.stylesToApply,
151+
style: styles.autolink,
152+
suppressHighlighting: true,
118153
},
119154
output(node.content, state),
120155
);
156+
state.withinLink = false;
157+
return link;
121158
};
122159

160+
const mentionedUsers = Array.isArray(mentioned_users)
161+
? mentioned_users.reduce((acc, cur) => {
162+
const userName = cur.name || cur.id || '';
163+
if (userName) {
164+
acc += `${acc.length ? '|' : ''}@${userName}`;
165+
}
166+
return acc;
167+
}, '')
168+
: '';
169+
170+
const regEx = new RegExp(`^\\B(${mentionedUsers})`, 'g');
171+
const match: MatchFunction = (source) => regEx.exec(source);
172+
const mentionsReact: ReactNodeOutput = (node, output, { ...state }) =>
173+
React.createElement(
174+
Text,
175+
{
176+
key: state.key,
177+
style: styles.mentions,
178+
},
179+
Array.isArray(node.content)
180+
? node.content[0]?.content || ''
181+
: output(node.content, state),
182+
);
183+
123184
const customRules = {
124185
link: { react },
125186
// we have no react rendering support for reflinks
126187
reflink: { match: () => null },
188+
...(mentionedUsers
189+
? {
190+
mentions: {
191+
match,
192+
order: defaultRules.text.order - 0.5,
193+
parse,
194+
react: mentionsReact,
195+
},
196+
}
197+
: {}),
127198
};
128199

129200
return (
130-
<Markdown rules={{ ...customRules, ...markdownRules }} styles={styles}>
201+
<Markdown
202+
onLink={onLink}
203+
rules={{
204+
...customRules,
205+
...markdownRules,
206+
}}
207+
styles={styles}
208+
>
131209
{newText}
132210
</Markdown>
133211
);

src/styles/themeConstants.ts

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ImageStyle, StyleProp, TextStyle, ViewStyle } from 'react-native';
1+
import type { ImageStyle, TextStyle, ViewStyle } from 'react-native';
22
import type { CSSObject } from 'styled-components';
33

44
export const BASE_FONT_SIZE = 16;
@@ -19,42 +19,49 @@ export type CSS = {
1919
};
2020

2121
export type MarkdownStyle = Partial<{
22-
blockQuoteBar: StyleProp<ViewStyle>;
23-
blockQuoteSection: StyleProp<ViewStyle>;
24-
blockQuoteSectionBar: StyleProp<ViewStyle>;
25-
blockQuoteText: StyleProp<ViewStyle>;
26-
codeBlock: StyleProp<TextStyle>;
27-
del: StyleProp<TextStyle>;
28-
em: StyleProp<TextStyle>;
29-
heading: StyleProp<TextStyle>;
30-
heading1: StyleProp<TextStyle>;
31-
heading2: StyleProp<TextStyle>;
32-
heading3: StyleProp<TextStyle>;
33-
heading4: StyleProp<TextStyle>;
34-
heading5: StyleProp<TextStyle>;
35-
heading6: StyleProp<TextStyle>;
36-
hr: StyleProp<ViewStyle>;
37-
image: StyleProp<ImageStyle>;
38-
inlineCode: StyleProp<TextStyle>;
39-
link: StyleProp<TextStyle>;
40-
listItem: StyleProp<ViewStyle>;
41-
listItemBulletType: string;
42-
listItemButton: StyleProp<TextStyle>;
43-
listItemNumber: StyleProp<TextStyle>;
44-
listItemText: StyleProp<TextStyle>;
45-
mailTo: StyleProp<TextStyle>;
46-
paragraph: StyleProp<ViewStyle>;
47-
strong: StyleProp<TextStyle>;
48-
table: StyleProp<ViewStyle>;
49-
tableHeader: StyleProp<ViewStyle>;
50-
tableHeaderCell: StyleProp<ViewStyle>;
51-
tableRow: StyleProp<ViewStyle>;
52-
tableRowCell: StyleProp<ViewStyle>;
53-
tableRowLast: StyleProp<ViewStyle>;
54-
text: StyleProp<TextStyle>;
55-
u: StyleProp<TextStyle>;
56-
video: StyleProp<ImageStyle>;
57-
view: StyleProp<ViewStyle>;
22+
autolink: TextStyle;
23+
blockQuoteBar: ViewStyle;
24+
blockQuoteSection: ViewStyle;
25+
blockQuoteSectionBar: ViewStyle;
26+
blockQuoteText: TextStyle | ViewStyle;
27+
br: TextStyle;
28+
codeBlock: TextStyle;
29+
del: TextStyle;
30+
em: TextStyle;
31+
heading: TextStyle;
32+
heading1: TextStyle;
33+
heading2: TextStyle;
34+
heading3: TextStyle;
35+
heading4: TextStyle;
36+
heading5: TextStyle;
37+
heading6: TextStyle;
38+
hr: ViewStyle;
39+
image: ImageStyle;
40+
inlineCode: TextStyle;
41+
list: ViewStyle;
42+
listItem: ViewStyle;
43+
listItemBullet: TextStyle;
44+
listItemNumber: TextStyle;
45+
listItemText: TextStyle;
46+
listRow: ViewStyle;
47+
mailTo: TextStyle;
48+
mentions: TextStyle;
49+
newline: TextStyle;
50+
noMargin: TextStyle;
51+
paragraph: TextStyle;
52+
paragraphCenter: TextStyle;
53+
paragraphWithImage: ViewStyle;
54+
strong: TextStyle;
55+
sublist: ViewStyle;
56+
table: ViewStyle;
57+
tableHeader: ViewStyle;
58+
tableHeaderCell: TextStyle;
59+
tableRow: ViewStyle;
60+
tableRowCell: ViewStyle;
61+
tableRowLast: ViewStyle;
62+
text: TextStyle;
63+
u: TextStyle;
64+
view: ViewStyle;
5865
}>;
5966

6067
export type Theme = {

0 commit comments

Comments
 (0)