|
1 | 1 | import React, { ComponentProps, ComponentType } from 'react'; |
2 | 2 | import emojiRegex from 'emoji-regex'; |
3 | | -import * as linkify from 'linkifyjs'; |
| 3 | +import { find } from 'linkifyjs'; |
4 | 4 | import { nanoid } from 'nanoid'; |
5 | 5 | import { findAndReplace, ReplaceFunction } from 'hast-util-find-and-replace'; |
6 | 6 | import ReactMarkdown, { Options, uriTransformer } from 'react-markdown'; |
@@ -239,52 +239,54 @@ export const renderText = < |
239 | 239 | const codeBlocks = messageCodeBlocks(newText); |
240 | 240 |
|
241 | 241 | // extract all valid links/emails within text and replace it with proper markup |
242 | | - uniqBy(linkify.find(newText), 'value').forEach(({ href, type, value }) => { |
243 | | - const linkIsInBlock = codeBlocks.some((block) => block?.includes(value)); |
244 | | - |
245 | | - // check if message is already markdown |
246 | | - const noParsingNeeded = |
247 | | - markdownLinks && |
248 | | - markdownLinks.filter((text) => { |
249 | | - const strippedHref = href?.replace(detectHttp, ''); |
250 | | - const strippedText = text?.replace(detectHttp, ''); |
251 | | - |
252 | | - if (!strippedHref || !strippedText) return false; |
253 | | - |
254 | | - return strippedHref.includes(strippedText) || strippedText.includes(strippedHref); |
255 | | - }); |
256 | | - |
257 | | - if (noParsingNeeded.length > 0 || linkIsInBlock) return; |
258 | | - |
259 | | - try { |
260 | | - // special case for mentions: |
261 | | - // it could happen that a user's name matches with an e-mail format pattern. |
262 | | - // in that case, we check whether the found e-mail is actually a mention |
263 | | - // by naively checking for an existence of @ sign in front of it. |
264 | | - if (type === 'email' && mentionedUsers) { |
265 | | - const emailMatchesWithName = mentionedUsers.some((u) => u.name === value); |
266 | | - if (emailMatchesWithName) { |
267 | | - newText = newText.replace(new RegExp(escapeRegExp(value), 'g'), (match, position) => { |
268 | | - const isMention = newText.charAt(position - 1) === '@'; |
269 | | - // in case of mention, we leave the match in its original form, |
270 | | - // and we let `mentionsMarkdownPlugin` to do its job |
271 | | - return isMention ? match : `[${match}](${encodeDecode(href)})`; |
272 | | - }); |
273 | | - |
274 | | - return; |
| 242 | + uniqBy([...find(newText, 'email'), ...find(newText, 'url')], 'value').forEach( |
| 243 | + ({ href, type, value }) => { |
| 244 | + const linkIsInBlock = codeBlocks.some((block) => block?.includes(value)); |
| 245 | + |
| 246 | + // check if message is already markdown |
| 247 | + const noParsingNeeded = |
| 248 | + markdownLinks && |
| 249 | + markdownLinks.filter((text) => { |
| 250 | + const strippedHref = href?.replace(detectHttp, ''); |
| 251 | + const strippedText = text?.replace(detectHttp, ''); |
| 252 | + |
| 253 | + if (!strippedHref || !strippedText) return false; |
| 254 | + |
| 255 | + return strippedHref.includes(strippedText) || strippedText.includes(strippedHref); |
| 256 | + }); |
| 257 | + |
| 258 | + if (noParsingNeeded.length > 0 || linkIsInBlock) return; |
| 259 | + |
| 260 | + try { |
| 261 | + // special case for mentions: |
| 262 | + // it could happen that a user's name matches with an e-mail format pattern. |
| 263 | + // in that case, we check whether the found e-mail is actually a mention |
| 264 | + // by naively checking for an existence of @ sign in front of it. |
| 265 | + if (type === 'email' && mentionedUsers) { |
| 266 | + const emailMatchesWithName = mentionedUsers.some((u) => u.name === value); |
| 267 | + if (emailMatchesWithName) { |
| 268 | + newText = newText.replace(new RegExp(escapeRegExp(value), 'g'), (match, position) => { |
| 269 | + const isMention = newText.charAt(position - 1) === '@'; |
| 270 | + // in case of mention, we leave the match in its original form, |
| 271 | + // and we let `mentionsMarkdownPlugin` to do its job |
| 272 | + return isMention ? match : `[${match}](${encodeDecode(href)})`; |
| 273 | + }); |
| 274 | + |
| 275 | + return; |
| 276 | + } |
275 | 277 | } |
276 | | - } |
277 | 278 |
|
278 | | - const displayLink = type === 'email' ? value : formatUrlForDisplay(href); |
| 279 | + const displayLink = type === 'email' ? value : formatUrlForDisplay(href); |
279 | 280 |
|
280 | | - newText = newText.replace( |
281 | | - new RegExp(escapeRegExp(value), 'g'), |
282 | | - `[${displayLink}](${encodeDecode(href)})`, |
283 | | - ); |
284 | | - } catch (e) { |
285 | | - void e; |
286 | | - } |
287 | | - }); |
| 281 | + newText = newText.replace( |
| 282 | + new RegExp(escapeRegExp(value), 'g'), |
| 283 | + `[${displayLink}](${encodeDecode(href)})`, |
| 284 | + ); |
| 285 | + } catch (e) { |
| 286 | + void e; |
| 287 | + } |
| 288 | + }, |
| 289 | + ); |
288 | 290 |
|
289 | 291 | const rehypePlugins = [emojiMarkdownPlugin]; |
290 | 292 |
|
|
0 commit comments