Refactor how message content highlighting works + change to safe HTML rendering component. Closes #2669

This commit is contained in:
Gabe Kangas
2023-02-04 17:21:06 -08:00
parent 388e4d3d78
commit e6d3da4f9c
7 changed files with 148 additions and 67 deletions

View File

@@ -1,11 +1,12 @@
/* eslint-disable react/no-danger */
import { FC, ReactNode, useEffect, useState } from 'react';
import { FC, ReactNode } from 'react';
import cn from 'classnames';
import { Tooltip } from 'antd';
import { useRecoilValue } from 'recoil';
import dynamic from 'next/dynamic';
import { decodeHTML } from 'entities';
import linkifyHtml from 'linkify-html';
import { Interweave } from 'interweave';
import { UrlMatcher } from 'interweave-autolink';
import { ChatMessageHighlightMatcher } from './customMatcher';
import styles from './ChatUserMessage.module.scss';
import { formatTimestamp } from './messageFmt';
import { ChatMessage } from '../../../interfaces/chat-message.model';
@@ -26,10 +27,6 @@ const ChatModerationActionMenu = dynamic(
},
);
const Highlight = dynamic(() => import('react-highlighter-ts').then(mod => mod.Highlight), {
ssr: false,
});
export type ChatUserMessageProps = {
message: ChatMessage;
showModeratorMenu: boolean;
@@ -71,7 +68,6 @@ export const ChatUserMessage: FC<ChatUserMessageProps> = ({
const color = `var(--theme-color-users-${displayColor})`;
const formattedTimestamp = `Sent ${formatTimestamp(timestamp)}`;
const [formattedMessage, setFormattedMessage] = useState<string>(body);
const badgeNodes = [];
if (isAuthorModerator) {
@@ -81,10 +77,6 @@ export const ChatUserMessage: FC<ChatUserMessageProps> = ({
badgeNodes.push(<AuthedUserBadge key="auth" userColor={displayColor} />);
}
useEffect(() => {
setFormattedMessage(decodeHTML(body));
}, [message]);
return (
<div
className={cn(
@@ -110,12 +102,14 @@ export const ChatUserMessage: FC<ChatUserMessageProps> = ({
</UserTooltip>
)}
<Tooltip title={formattedTimestamp} mouseEnterDelay={1}>
<Highlight search={highlightString}>
<div
className={styles.message}
dangerouslySetInnerHTML={{ __html: linkifyHtml(formattedMessage) }}
/>
</Highlight>
<Interweave
className={styles.message}
content={body}
matchers={[
new UrlMatcher('url', { validateTLD: false }),
new ChatMessageHighlightMatcher('highlight', { highlightString }),
]}
/>
</Tooltip>
{showModeratorMenu && (
<div className={styles.modMenuWrapper}>