// Copyright 2018 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import type { KeyboardEvent } from 'react'; import React from 'react'; import type { AttachmentType } from '../../types/Attachment'; import { canBeDownloaded } from '../../types/Attachment'; import type { SizeClassType } from '../emoji/lib'; import { getSizeClass } from '../emoji/lib'; import { AtMentionify } from './AtMentionify'; import { Emojify } from './Emojify'; import { AddNewLines } from './AddNewLines'; import { Linkify } from './Linkify'; import type { ShowConversationType } from '../../state/ducks/conversations'; import type { HydratedBodyRangesType, LocalizerType, RenderTextCallbackType, } from '../../types/Util'; export type Props = { author?: string; bodyRanges?: HydratedBodyRangesType; direction?: 'incoming' | 'outgoing'; /** If set, all emoji will be the same size. Otherwise, just one emoji will be large. */ disableJumbomoji?: boolean; /** If set, links will be left alone instead of turned into clickable `` tags. */ disableLinks?: boolean; i18n: LocalizerType; kickOffBodyDownload?: () => void; onIncreaseTextLength?: () => unknown; showConversation?: ShowConversationType; text: string; textAttachment?: Pick; }; const renderEmoji = ({ text, key, sizeClass, renderNonEmoji, }: { i18n: LocalizerType; text: string; key: number; sizeClass?: SizeClassType; renderNonEmoji: RenderTextCallbackType; }) => ( ); /** * This component makes it very easy to use all three of our message formatting * components: `Emojify`, `Linkify`, and `AddNewLines`. Because each of them is fully * configurable with their `renderXXX` props, this component will assemble all three of * them for you. */ export function MessageBody({ author, bodyRanges, direction, disableJumbomoji, disableLinks, i18n, kickOffBodyDownload, onIncreaseTextLength, showConversation, text, textAttachment, }: Props): JSX.Element { const hasReadMore = Boolean(onIncreaseTextLength); const textWithSuffix = textAttachment?.pending || hasReadMore ? `${text}...` : text; const sizeClass = disableJumbomoji ? undefined : getSizeClass(text); const processedText = AtMentionify.preprocessMentions( textWithSuffix, bodyRanges ); const renderNewLines: RenderTextCallbackType = ({ text: textWithNewLines, key, }) => { return ( ( )} /> ); }; let pendingContent: React.ReactNode; if (hasReadMore) { pendingContent = null; } else if (textAttachment?.pending) { pendingContent = ( {i18n('downloading')} ); } else if ( textAttachment && canBeDownloaded(textAttachment) && kickOffBodyDownload ) { pendingContent = ( {' '} ); } return ( {author && ( <> {renderEmoji({ i18n, text: author, sizeClass, key: 0, renderNonEmoji: renderNewLines, })} :{' '} )} {disableLinks ? ( renderEmoji({ i18n, text: processedText, sizeClass, key: 0, renderNonEmoji: renderNewLines, }) ) : ( { return renderEmoji({ i18n, text: nonLinkText, sizeClass, key, renderNonEmoji: renderNewLines, }); }} /> )} {pendingContent} {onIncreaseTextLength ? ( ) : null} ); }