diff --git a/src/CONST.js b/src/CONST.js
index e3a88d48cd7e..c0e26e78fca7 100755
--- a/src/CONST.js
+++ b/src/CONST.js
@@ -387,6 +387,8 @@ const CONST = {
EMOJI_FREQUENT_ROW_COUNT: 3,
+ EMOJI_INVISIBLE_CODEPOINT: 'fe0f',
+
TOOLTIP_MAX_LINES: 3,
LOGIN_TYPE: {
diff --git a/src/libs/EmojiUtils.js b/src/libs/EmojiUtils.js
index 61684d37d0f9..208dd6b1cf4d 100644
--- a/src/libs/EmojiUtils.js
+++ b/src/libs/EmojiUtils.js
@@ -9,7 +9,7 @@ import * as User from './actions/User';
* @param {String} input
* @returns {String}
*/
-function getEmojiUnicode(input) {
+const getEmojiUnicode = _.memoize((input) => {
if (input.length === 0) {
return '';
}
@@ -40,7 +40,7 @@ function getEmojiUnicode(input) {
}
}
return _.map(pairs, val => parseInt(val, 10).toString(16)).join(' ');
-}
+});
/**
* Function to remove Skin Tone and utf16 surrogates from Emoji
@@ -70,6 +70,34 @@ function isSingleEmoji(message) {
return matchedUnicode === currentMessageUnicode;
}
+/**
+ * Validates that this message contains only emojis
+ *
+ * @param {String} message
+ * @returns {Boolean}
+ */
+function containsOnlyEmojis(message) {
+ const trimmedMessage = message.replace(/ /g, '').replaceAll('\n', '');
+ const match = trimmedMessage.match(CONST.REGEX.EMOJIS);
+
+ if (!match) {
+ return false;
+ }
+
+ const codes = [];
+ _.map(match, emoji => _.map(getEmojiUnicode(emoji).split(' '), (code) => {
+ if (code !== CONST.EMOJI_INVISIBLE_CODEPOINT) {
+ codes.push(code);
+ }
+ return code;
+ }));
+
+ // Emojis are stored as multiple characters, so we're using spread operator
+ // to iterate over the actual emojis, not just characters that compose them
+ const messageCodes = _.filter(_.map([...trimmedMessage], char => getEmojiUnicode(char)), string => string.length > 0 && string !== CONST.EMOJI_INVISIBLE_CODEPOINT);
+ return codes.length === messageCodes.length;
+}
+
/**
* Get the header indices based on the max emojis per row
* @param {Object[]} emojis
@@ -176,4 +204,5 @@ export {
getDynamicHeaderIndices,
mergeEmojisWithFrequentlyUsedEmojis,
addToFrequentlyUsedEmojis,
+ containsOnlyEmojis,
};
diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js
index 194a865636f7..8cfcfe9aac73 100644
--- a/src/pages/home/report/ReportActionItemFragment.js
+++ b/src/pages/home/report/ReportActionItemFragment.js
@@ -68,7 +68,7 @@ const defaultProps = {
const ReportActionItemFragment = (props) => {
switch (props.fragment.type) {
- case 'COMMENT':
+ case 'COMMENT': {
// If this is an attachment placeholder, return the placeholder component
if (props.isAttachment && props.loading) {
return (
@@ -97,6 +97,16 @@ const ReportActionItemFragment = (props) => {
);
}
+ // If the only difference between fragment.text and fragment.html is
tags
+ // we replace them with line breaks and render it as text, not as html.
+ // This is done to render emojis with line breaks between them as text.
+ const differByLineBreaksOnly = props.fragment.html.replaceAll('
', ' ') === props.fragment.text;
+ if (differByLineBreaksOnly) {
+ const textWithLineBreaks = props.fragment.html.replaceAll('
', '\n');
+ // eslint-disable-next-line no-param-reassign
+ props.fragment = {...props.fragment, text: textWithLineBreaks, html: textWithLineBreaks};
+ }
+
// Only render HTML if we have html in the fragment
return props.fragment.html !== props.fragment.text
? (
@@ -106,7 +116,7 @@ const ReportActionItemFragment = (props) => {
) : (
{Str.htmlDecode(props.fragment.text)}
{props.fragment.isEdited && (
@@ -119,6 +129,7 @@ const ReportActionItemFragment = (props) => {
)}
);
+ }
case 'TEXT':
return (
diff --git a/src/styles/styles.js b/src/styles/styles.js
index f222d4f56246..4859c0470350 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -1042,9 +1042,9 @@ const styles = {
textDecorationLine: 'none',
},
- singleEmojiText: {
- fontSize: variables.fontSizeSingleEmoji,
- lineHeight: variables.fontSizeSingleEmojiHeight,
+ onlyEmojisText: {
+ fontSize: variables.fontSizeOnlyEmojis,
+ lineHeight: variables.fontSizeOnlyEmojisHeight,
},
createMenuPositionSidebar: {
diff --git a/src/styles/variables.js b/src/styles/variables.js
index 4302947ac879..506755712154 100644
--- a/src/styles/variables.js
+++ b/src/styles/variables.js
@@ -14,8 +14,8 @@ export default {
avatarSizeSmall: 28,
avatarSizeSubscript: 20,
avatarSizeSmallSubscript: 14,
- fontSizeSingleEmoji: 30,
- fontSizeSingleEmojiHeight: 35,
+ fontSizeOnlyEmojis: 30,
+ fontSizeOnlyEmojisHeight: 35,
fontSizeSmall: 11,
fontSizeExtraSmall: 9,
fontSizeLabel: 13,