From 9d424058aa2e719c55c24f83b0100bd487fbab74 Mon Sep 17 00:00:00 2001 From: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com> Date: Fri, 14 Oct 2022 23:05:43 +0530 Subject: [PATCH] [IMPROVE] Respect convert ascii to emoji preference for new message template (#27038) --- .../components/MessageContentBody.tsx | 6 ++- packages/gazzodown/src/Markup.spec.tsx | 31 ++++++++++++- .../gazzodown/src/MarkupInteractionContext.ts | 1 + packages/gazzodown/src/emoji/Emoji.tsx | 39 +++++----------- .../gazzodown/src/emoji/EmojiRenderer.tsx | 45 +++++++++++++++++++ 5 files changed, 90 insertions(+), 32 deletions(-) create mode 100644 packages/gazzodown/src/emoji/EmojiRenderer.tsx diff --git a/apps/meteor/client/views/room/MessageList/components/MessageContentBody.tsx b/apps/meteor/client/views/room/MessageList/components/MessageContentBody.tsx index 2e666792f352..0088d68e64a5 100644 --- a/apps/meteor/client/views/room/MessageList/components/MessageContentBody.tsx +++ b/apps/meteor/client/views/room/MessageList/components/MessageContentBody.tsx @@ -3,7 +3,7 @@ import { Box, MessageBody } from '@rocket.chat/fuselage'; import colors from '@rocket.chat/fuselage-tokens/colors'; import { MarkupInteractionContext, Markup, UserMention, ChannelMention } from '@rocket.chat/gazzodown'; import { escapeRegExp } from '@rocket.chat/string-helpers'; -import { useLayout } from '@rocket.chat/ui-contexts'; +import { useLayout, useUserPreference } from '@rocket.chat/ui-contexts'; import { FlowRouter } from 'meteor/kadira:flow-router'; import React, { ReactElement, UIEvent, useCallback, useMemo } from 'react'; @@ -19,7 +19,6 @@ const detectEmoji = (text: string): { name: string; className: string; image?: s const html = Object.values(emoji.packages) .reverse() .reduce((html, { render }) => render(html), text); - const div = document.createElement('div'); div.innerHTML = html; return Array.from(div.querySelectorAll('span')).map((span) => ({ @@ -125,6 +124,8 @@ const MessageContentBody = ({ mentions, channels, md }: MessageContentBodyProps) } `; + const convertAsciiToEmoji = useUserPreference('convertAsciiEmoji', true); + return ( @@ -136,6 +137,7 @@ const MessageContentBody = ({ mentions, channels, md }: MessageContentBodyProps) onUserMentionClick, resolveChannelMention, onChannelMentionClick, + convertAsciiToEmoji, }} > diff --git a/packages/gazzodown/src/Markup.spec.tsx b/packages/gazzodown/src/Markup.spec.tsx index 191b16b4c3b2..32d3426c0aad 100644 --- a/packages/gazzodown/src/Markup.spec.tsx +++ b/packages/gazzodown/src/Markup.spec.tsx @@ -1,9 +1,9 @@ import { render, screen, cleanup, waitFor } from '@testing-library/react'; import { Suspense } from 'react'; -import Markup from './Markup'; - import '@testing-library/jest-dom'; +import { MarkupInteractionContext } from '.'; +import Markup from './Markup'; afterEach(cleanup); @@ -33,6 +33,33 @@ it('renders a big emoji block', () => { expect(screen.getAllByRole('img', { name: ':smile:' })).toHaveLength(2); }); +it('renders a big emoji block with ASCII emoji', () => { + render( + + + , + ); + + expect(screen.getByRole('presentation')).toHaveTextContent(':slight_smile:🙂:)'); + expect(screen.getAllByRole('img')).toHaveLength(2); + expect(screen.getAllByRole('img', { name: ':slight_smile:' })).toHaveLength(1); +}); + it('renders a paragraph', () => { render( ((e: UIEvent) => void) | undefined; resolveChannelMention?: (mention: string) => ChannelMention | undefined; onChannelMentionClick?: (mentionedChannel: ChannelMention) => ((e: UIEvent) => void) | undefined; + convertAsciiToEmoji?: boolean; }; export const MarkupInteractionContext = createContext({}); diff --git a/packages/gazzodown/src/emoji/Emoji.tsx b/packages/gazzodown/src/emoji/Emoji.tsx index 1052d426d5f5..fa5e13637dec 100644 --- a/packages/gazzodown/src/emoji/Emoji.tsx +++ b/packages/gazzodown/src/emoji/Emoji.tsx @@ -1,8 +1,9 @@ -import { MessageEmoji, ThreadMessageEmoji } from '@rocket.chat/fuselage'; import type * as MessageParser from '@rocket.chat/message-parser'; import { ReactElement, useMemo, useContext, memo } from 'react'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; +import PlainSpan from '../elements/PlainSpan'; +import EmojiRenderer from './EmojiRenderer'; type EmojiProps = MessageParser.Emoji & { big?: boolean; @@ -10,36 +11,18 @@ type EmojiProps = MessageParser.Emoji & { }; const Emoji = ({ big = false, preview = false, ...emoji }: EmojiProps): ReactElement => { - const { detectEmoji } = useContext(MarkupInteractionContext); + const { convertAsciiToEmoji } = useContext(MarkupInteractionContext); - const fallback = useMemo(() => ('unicode' in emoji ? emoji.unicode : `:${emoji.shortCode ?? emoji.value.value}:`), [emoji]); + const asciiEmoji = useMemo( + () => ('shortCode' in emoji && emoji.value.value !== emoji.shortCode ? emoji.value.value : undefined), + [emoji], + ); - const descriptors = useMemo(() => { - const detected = detectEmoji?.(fallback); - return detected?.length !== 0 ? detected : undefined; - }, [detectEmoji, fallback]); + if (!convertAsciiToEmoji && asciiEmoji) { + return ; + } - return ( - <> - {descriptors?.map(({ name, className, image, content }, i) => ( - - {preview ? ( - - {content} - - ) : ( - - {content} - - )} - - )) ?? ( - - {fallback} - - )} - - ); + return ; }; export default memo(Emoji); diff --git a/packages/gazzodown/src/emoji/EmojiRenderer.tsx b/packages/gazzodown/src/emoji/EmojiRenderer.tsx new file mode 100644 index 000000000000..7a4ca5324930 --- /dev/null +++ b/packages/gazzodown/src/emoji/EmojiRenderer.tsx @@ -0,0 +1,45 @@ +import { MessageEmoji, ThreadMessageEmoji } from '@rocket.chat/fuselage'; +import type * as MessageParser from '@rocket.chat/message-parser'; +import { ReactElement, useMemo, useContext, memo } from 'react'; + +import { MarkupInteractionContext } from '../MarkupInteractionContext'; + +type EmojiProps = MessageParser.Emoji & { + big?: boolean; + preview?: boolean; +}; + +const EmojiRenderer = ({ big = false, preview = false, ...emoji }: EmojiProps): ReactElement => { + const { detectEmoji } = useContext(MarkupInteractionContext); + + const fallback = useMemo(() => ('unicode' in emoji ? emoji.unicode : `:${emoji.shortCode ?? emoji.value.value}:`), [emoji]); + + const descriptors = useMemo(() => { + const detected = detectEmoji?.(fallback); + return detected?.length !== 0 ? detected : undefined; + }, [detectEmoji, fallback]); + + return ( + <> + {descriptors?.map(({ name, className, image, content }, i) => ( + + {preview ? ( + + {content} + + ) : ( + + {content} + + )} + + )) ?? ( + + {fallback} + + )} + + ); +}; + +export default memo(EmojiRenderer);