104 lines
3.2 KiB
TypeScript
104 lines
3.2 KiB
TypeScript
import React, {
|
|
memo, useMemo, useRef,
|
|
} from '../../lib/teact/teact';
|
|
|
|
import type { ApiFormattedText, ApiMessage } from '../../api/types';
|
|
import type { ObserveFn } from '../../hooks/useIntersectionObserver';
|
|
|
|
import { ApiMessageEntityTypes } from '../../api/types';
|
|
import trimText from '../../util/trimText';
|
|
import { extractMessageText, getMessageText, stripCustomEmoji } from '../../global/helpers';
|
|
import { renderTextWithEntities } from './helpers/renderTextWithEntities';
|
|
import useSyncEffect from '../../hooks/useSyncEffect';
|
|
|
|
interface OwnProps {
|
|
message: ApiMessage;
|
|
translatedText?: ApiFormattedText;
|
|
isForAnimation?: boolean;
|
|
emojiSize?: number;
|
|
highlight?: string;
|
|
isSimple?: boolean;
|
|
truncateLength?: number;
|
|
isProtected?: boolean;
|
|
observeIntersectionForLoading?: ObserveFn;
|
|
observeIntersectionForPlaying?: ObserveFn;
|
|
withTranslucentThumbs?: boolean;
|
|
shouldRenderAsHtml?: boolean;
|
|
inChatList?: boolean;
|
|
}
|
|
|
|
const MIN_CUSTOM_EMOJIS_FOR_SHARED_CANVAS = 3;
|
|
|
|
function MessageText({
|
|
message,
|
|
translatedText,
|
|
isForAnimation,
|
|
emojiSize,
|
|
highlight,
|
|
isSimple,
|
|
truncateLength,
|
|
isProtected,
|
|
observeIntersectionForLoading,
|
|
observeIntersectionForPlaying,
|
|
withTranslucentThumbs,
|
|
shouldRenderAsHtml,
|
|
inChatList,
|
|
}: OwnProps) {
|
|
// eslint-disable-next-line no-null/no-null
|
|
const sharedCanvasRef = useRef<HTMLCanvasElement>(null);
|
|
// eslint-disable-next-line no-null/no-null
|
|
const sharedCanvasHqRef = useRef<HTMLCanvasElement>(null);
|
|
|
|
const textCacheBusterRef = useRef(0);
|
|
|
|
const formattedText = translatedText || extractMessageText(message, inChatList);
|
|
const adaptedFormattedText = isForAnimation && formattedText ? stripCustomEmoji(formattedText) : formattedText;
|
|
const { text, entities } = adaptedFormattedText || {};
|
|
|
|
useSyncEffect(() => {
|
|
textCacheBusterRef.current += 1;
|
|
}, [text, entities]);
|
|
|
|
const withSharedCanvas = useMemo(() => {
|
|
const hasSpoilers = entities?.some((e) => e.type === ApiMessageEntityTypes.Spoiler);
|
|
if (hasSpoilers) {
|
|
return false;
|
|
}
|
|
|
|
const customEmojisCount = entities?.filter((e) => e.type === ApiMessageEntityTypes.CustomEmoji).length || 0;
|
|
return customEmojisCount >= MIN_CUSTOM_EMOJIS_FOR_SHARED_CANVAS;
|
|
}, [entities]) || 0;
|
|
|
|
if (!text) {
|
|
const contentNotSupportedText = getMessageText(message);
|
|
return contentNotSupportedText ? [trimText(contentNotSupportedText, truncateLength)] : undefined as any;
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{[
|
|
withSharedCanvas && <canvas ref={sharedCanvasRef} className="shared-canvas" />,
|
|
withSharedCanvas && <canvas ref={sharedCanvasHqRef} className="shared-canvas" />,
|
|
renderTextWithEntities({
|
|
text: trimText(text!, truncateLength),
|
|
entities,
|
|
highlight,
|
|
emojiSize,
|
|
shouldRenderAsHtml,
|
|
messageId: message.id,
|
|
isSimple,
|
|
isProtected,
|
|
observeIntersectionForLoading,
|
|
observeIntersectionForPlaying,
|
|
withTranslucentThumbs,
|
|
sharedCanvasRef,
|
|
sharedCanvasHqRef,
|
|
cacheBuster: textCacheBusterRef.current.toString(),
|
|
}),
|
|
].flat().filter(Boolean)}
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default memo(MessageText);
|