Skip to content

Commit 651b33f

Browse files
Merge pull request #505 from GetStream/update-markdown-lib
replacing the antique markdown lib with a newer one for fixing some issues
2 parents 2c9b87e + 085a24f commit 651b33f

File tree

14 files changed

+246
-153
lines changed

14 files changed

+246
-153
lines changed

docs/build/bundle.7ded6173.js

Lines changed: 0 additions & 2 deletions
This file was deleted.

docs/build/bundle.d56b9596.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/build/bundle.7ded6173.js.LICENSE.txt renamed to docs/build/bundle.d56b9596.js.LICENSE.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ object-assign
4747

4848
/*! https://mths.be/regenerate v1.4.1 by @mathias | MIT license */
4949

50+
/**
51+
* @license
52+
* Lodash <https://lodash.com/>
53+
* Copyright OpenJS Foundation and other contributors <https://openjsf.org/>
54+
* Released under MIT license <https://lodash.com/license>
55+
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
56+
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
57+
*/
58+
5059
/**
5160
* A better abstraction over CSS.
5261
*

docs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99
</head>
1010
<body>
1111
<div id="rsg-root"></div>
12-
<script src="build/bundle.7ded6173.js"></script>
12+
<script src="build/bundle.d56b9596.js"></script>
1313
</body>
1414
</html>

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/__tests__/__snapshots__/MessageTextContainer.test.js.snap

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ exports[`MessageTextContainer should render message text container 1`] = `
2727
style={
2828
Array [
2929
Object {
30-
"minHeight": 1,
31-
"minWidth": 1,
30+
"alignSelf": "stretch",
3231
},
3332
undefined,
3433
]
@@ -41,17 +40,16 @@ exports[`MessageTextContainer should render message text container 1`] = `
4140
"flexDirection": "row",
4241
"flexWrap": "wrap",
4342
"justifyContent": "flex-start",
43+
"marginBottom": 0,
44+
"marginTop": 0,
4445
}
4546
}
4647
>
4748
<Text
4849
style={
49-
Array [
50-
Object {
51-
"color": "#222222",
52-
},
53-
undefined,
54-
]
50+
Object {
51+
"color": "#222222",
52+
}
5553
}
5654
>
5755
Hello World

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
);

0 commit comments

Comments
 (0)