Skip to content
85 changes: 85 additions & 0 deletions app/containers/Emoji/Emoji.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import { Text, useWindowDimensions } from 'react-native';
import type { StyleProp, TextStyle } from 'react-native';

import { useTheme } from '../../theme';
import useShortnameToUnicode from '../../lib/hooks/useShortnameToUnicode';
import CustomEmoji from '../EmojiPicker/CustomEmoji';
import { useAppSelector } from '../../lib/hooks/useAppSelector';
import { getUserSelector } from '../../selectors/login';
import { useResponsiveLayout } from '../../lib/hooks/useResponsiveLayout/useResponsiveLayout';

interface ISharedEmojiProps {
literal?: string;
isBigEmoji?: boolean;
style?: StyleProp<TextStyle>;
isAvatar?: boolean;
getCustomEmoji?: (name: string) => any;
customEmoji?: any;
}

const Emoji = ({ literal, isBigEmoji, style, isAvatar, getCustomEmoji, customEmoji }: ISharedEmojiProps) => {
const { colors } = useTheme();
const { formatShortnameToUnicode } = useShortnameToUnicode();
const { fontScale } = useWindowDimensions();
const { fontScaleLimited } = useResponsiveLayout();
const convertAsciiEmoji = useAppSelector(state => getUserSelector(state)?.settings?.preferences?.convertAsciiEmoji);

if (customEmoji) {
const customEmojiSize = {
width: 15 * fontScale,
height: 15 * fontScale
};
const customEmojiBigSize = {
width: 30 * fontScale,
height: 30 * fontScale
};
return <CustomEmoji style={[isBigEmoji ? customEmojiBigSize : customEmojiSize, style]} emoji={customEmoji} />;
}

if (!literal) {
return null;
}

const emojiUnicode = formatShortnameToUnicode(literal);
const emojiName = literal.replace(/:/g, '');
const foundCustomEmoji = getCustomEmoji?.(emojiName);

if (foundCustomEmoji) {
const customEmojiSize = {
width: 15 * fontScale,
height: 15 * fontScale
};
const customEmojiBigSize = {
width: 30 * fontScale,
height: 30 * fontScale
};
return <CustomEmoji style={[isBigEmoji ? customEmojiBigSize : customEmojiSize, style]} emoji={foundCustomEmoji} />;
}

// Handle ASCII emojis if needed, though usually handled by parser or formatShortnameToUnicode if configured
// But here we follow the logic from markdown/components/emoji/Emoji.tsx
// logic for ASCII is a bit specific to the block structure there, but here we deal with string literal.
// If formatShortnameToUnicode returns the same string, it might be an ASCII or unknown.

const avatarStyle = {
fontSize: 30 * fontScaleLimited,
lineHeight: 30 * fontScaleLimited,
textAlign: 'center',
textAlignVertical: 'center'
};

return (
<Text
style={[
{ color: colors.fontDefault },
isBigEmoji ? { fontSize: 30, lineHeight: 43 } : { fontSize: 16, lineHeight: 22 },
style,
isAvatar && avatarStyle
]}>
{emojiUnicode}
</Text>
);
};

export default Emoji;
1 change: 1 addition & 0 deletions app/containers/Emoji/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Emoji } from './Emoji';
11 changes: 3 additions & 8 deletions app/containers/EmojiPicker/Emoji.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
import React from 'react';
import { Text } from 'react-native';

import useShortnameToUnicode from '../../lib/hooks/useShortnameToUnicode';
import styles from './styles';
import CustomEmoji from './CustomEmoji';
import { type IEmojiProps } from './interfaces';
import SharedEmoji from '../Emoji/Emoji';

export const Emoji = ({ emoji }: IEmojiProps): React.ReactElement => {
const { formatShortnameToUnicode } = useShortnameToUnicode(true);
const unicodeEmoji = formatShortnameToUnicode(`:${emoji}:`);

if (typeof emoji === 'string') {
return <Text style={styles.categoryEmoji}>{unicodeEmoji}</Text>;
return <SharedEmoji literal={`:${emoji}:`} style={styles.categoryEmoji} />;
}
return <CustomEmoji style={styles.customCategoryEmoji} emoji={emoji} />;
return <SharedEmoji customEmoji={emoji} style={styles.customCategoryEmoji} />;
};
68 changes: 6 additions & 62 deletions app/containers/markdown/components/emoji/Emoji.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import React, { useContext } from 'react';
import { Text, useWindowDimensions } from 'react-native';
import { type Emoji as EmojiProps } from '@rocket.chat/message-parser';

import Plain from '../Plain';
import useShortnameToUnicode from '../../../../lib/hooks/useShortnameToUnicode';
import { useTheme } from '../../../../theme';
import styles from '../../styles';
import CustomEmoji from '../../../EmojiPicker/CustomEmoji';
import MarkdownContext from '../../contexts/MarkdownContext';
import { useAppSelector } from '../../../../lib/hooks/useAppSelector';
import { getUserSelector } from '../../../../selectors/login';
import { useResponsiveLayout } from '../../../../lib/hooks/useResponsiveLayout/useResponsiveLayout';
import SharedEmoji from '../../../Emoji/Emoji';

interface IEmojiProps {
block: EmojiProps;
Expand All @@ -20,69 +12,21 @@ interface IEmojiProps {
isAvatar?: boolean;
}

function getEmojiToken(block: EmojiProps, isAvatar: boolean) {
const getEmojiToken = (block: EmojiProps, isAvatar: boolean) => {
if ('unicode' in block) {
return block.unicode;
}

if (isAvatar) {
return block.value?.value;
}

return block?.shortCode ? `:${block.shortCode}:` : `:${block.value?.value}:`;
}
};

const Emoji = ({ block, isBigEmoji, style = {}, index, isAvatar = false }: IEmojiProps) => {
const { colors } = useTheme();
const Emoji = ({ block, isBigEmoji, style, index, isAvatar }: IEmojiProps) => {
const { getCustomEmoji } = useContext(MarkdownContext);
const { fontScale } = useWindowDimensions();
const { fontScaleLimited } = useResponsiveLayout();
const { formatShortnameToUnicode } = useShortnameToUnicode();
const spaceLeft = index && index > 0 ? ' ' : '';
const convertAsciiEmoji = useAppSelector(state => getUserSelector(state)?.settings?.preferences?.convertAsciiEmoji);

if ('unicode' in block) {
return <Text style={[{ color: colors.fontDefault }, isBigEmoji ? styles.textBig : styles.text]}>{block.unicode}</Text>;
}

const emojiToken = getEmojiToken(block, isAvatar);
const emojiUnicode = formatShortnameToUnicode(emojiToken);
const emoji = getCustomEmoji?.(block.value?.value.replace(/\:/g, ''));
const isAsciiEmoji = !!block?.shortCode && block.value?.value !== block?.shortCode;
const displayAsciiEmoji = !convertAsciiEmoji && isAsciiEmoji && !!block.value;
const customEmojiSize = {
width: 15 * fontScale,
height: 15 * fontScale
};

const customEmojiBigSize = {
width: 30 * fontScale,
height: 30 * fontScale
};

const avatarStyle = {
fontSize: 30 * fontScaleLimited,
lineHeight: 30 * fontScaleLimited,
textAlign: 'center',
textAlignVertical: 'center'
};

if (emoji) {
return <CustomEmoji style={[isBigEmoji ? customEmojiBigSize : customEmojiSize, style]} emoji={emoji} />;
}
const literal = getEmojiToken(block, !!isAvatar);

return (
<Text
style={[
{ color: colors.fontDefault },
isBigEmoji && emojiToken !== emojiUnicode ? styles.textBig : styles.text,
style,
isAvatar && avatarStyle
]}>
{spaceLeft}
{displayAsciiEmoji ? <Plain value={block.value!.value} /> : emojiUnicode}
</Text>
);
return <SharedEmoji literal={literal} isBigEmoji={isBigEmoji} style={style} isAvatar={isAvatar} getCustomEmoji={getCustomEmoji} />;
};

export default Emoji;