11import React from 'react' ;
22import { Linking , Text } from 'react-native' ;
3- // @ts -expect-error
4- import Markdown from '@stream-io/react-native-simple-markdown' ;
53import anchorme from 'anchorme' ;
64import 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
1016import type { MarkdownStyle } from '../../../../styles/themeConstants' ;
1117import 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+
4262export 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
5677export 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