1
1
import Anser , { AnserJsonEntry } from "anser" ;
2
2
import { escapeCarriageReturn } from "escape-carriage" ;
3
+ import linkifyit from "linkify-it" ;
3
4
import * as React from "react" ;
4
5
5
6
/**
@@ -101,9 +102,8 @@ function createStyle(bundle: AnserJsonEntry): React.CSSProperties {
101
102
* @param bundle Anser output.
102
103
* @param key
103
104
*/
104
-
105
105
function convertBundleIntoReact (
106
- linkify : boolean ,
106
+ linkify : boolean | "fuzzy" ,
107
107
useClasses : boolean ,
108
108
bundle : AnserJsonEntry ,
109
109
key : number
@@ -119,6 +119,19 @@ function convertBundleIntoReact(
119
119
) ;
120
120
}
121
121
122
+ if ( linkify === "fuzzy" ) {
123
+ return linkWithLinkify ( bundle , key , style , className ) ;
124
+ }
125
+
126
+ return linkWithClassicMode ( bundle , key , style , className ) ;
127
+ }
128
+
129
+ function linkWithClassicMode (
130
+ bundle : AnserJsonEntry ,
131
+ key : number ,
132
+ style : React . CSSProperties | null ,
133
+ className : string | null
134
+ ) {
122
135
const content : React . ReactNode [ ] = [ ] ;
123
136
const linkRegex = / ( \s | ^ ) ( h t t p s ? : \/ \/ (?: w w w \. | (? ! w w w ) ) [ ^ \s . ] + \. [ ^ \s ] { 2 , } | w w w \. [ ^ \s ] + \. [ ^ \s ] { 2 , } ) / g;
124
137
@@ -157,9 +170,70 @@ function convertBundleIntoReact(
157
170
return React . createElement ( "span" , { style, key, className } , content ) ;
158
171
}
159
172
173
+ function linkWithLinkify (
174
+ bundle : AnserJsonEntry ,
175
+ key : number ,
176
+ style : React . CSSProperties | null ,
177
+ className : string | null
178
+ ) : JSX . Element {
179
+ const linker = linkifyit ( { fuzzyEmail : false } ) . tlds ( [ "io" ] , true ) ;
180
+
181
+ if ( ! linker . pretest ( bundle . content ) ) {
182
+ return React . createElement (
183
+ "span" ,
184
+ { style, key, className } ,
185
+ bundle . content
186
+ ) ;
187
+ }
188
+
189
+ const matches = linker . match ( bundle . content ) ;
190
+
191
+ if ( ! matches ) {
192
+ return React . createElement (
193
+ "span" ,
194
+ { style, key, className } ,
195
+ bundle . content
196
+ ) ;
197
+ }
198
+
199
+ const content : React . ReactNode [ ] = [
200
+ bundle . content . substring ( 0 , matches [ 0 ] ?. index ) ,
201
+ ] ;
202
+
203
+ matches . forEach ( ( match , i ) => {
204
+ content . push (
205
+ React . createElement (
206
+ "a" ,
207
+ {
208
+ href : match . url ,
209
+ target : "_blank" ,
210
+ key : i ,
211
+ } ,
212
+ bundle . content . substring ( match . index , match . lastIndex )
213
+ )
214
+ ) ;
215
+
216
+ if ( matches [ i + 1 ] ) {
217
+ content . push (
218
+ bundle . content . substring ( matches [ i ] . lastIndex , matches [ i + 1 ] ?. index )
219
+ ) ;
220
+ }
221
+ } ) ;
222
+
223
+ if ( matches [ matches . length - 1 ] . lastIndex !== bundle . content . length ) {
224
+ content . push (
225
+ bundle . content . substring (
226
+ matches [ matches . length - 1 ] . lastIndex ,
227
+ bundle . content . length
228
+ )
229
+ ) ;
230
+ }
231
+ return React . createElement ( "span" , { style, key, className } , content ) ;
232
+ }
233
+
160
234
declare interface Props {
161
235
children ?: string ;
162
- linkify ?: boolean ;
236
+ linkify ?: boolean | "fuzzy" ;
163
237
className ?: string ;
164
238
useClasses ?: boolean ;
165
239
}
0 commit comments