diff --git a/ts/components/conversation/Emojify.stories.tsx b/ts/components/conversation/Emojify.stories.tsx
index 547b03da9e..edb62cea67 100644
--- a/ts/components/conversation/Emojify.stories.tsx
+++ b/ts/components/conversation/Emojify.stories.tsx
@@ -96,3 +96,19 @@ story.add('Custom Text Render', () => {
return ;
});
+
+story.add('Tens of thousands of emoji', () => {
+ const props = createProps({
+ text: 'π
'.repeat(40000),
+ });
+
+ return ;
+});
+
+story.add('Tens of thousands of emoji, interspersed with text', () => {
+ const props = createProps({
+ text: 'π
hi '.repeat(40000),
+ });
+
+ return ;
+});
diff --git a/ts/test-both/util/emoji_test.ts b/ts/test-both/util/emoji_test.ts
index 0eb24968d0..c86081df67 100644
--- a/ts/test-both/util/emoji_test.ts
+++ b/ts/test-both/util/emoji_test.ts
@@ -28,25 +28,15 @@ describe('emoji', () => {
{ type: 'emoji', value: 'π' },
{ type: 'text', value: 'world' },
{ type: 'emoji', value: 'π' },
- { type: 'text', value: '' },
{ type: 'emoji', value: 'π' },
{ type: 'text', value: '!' },
]);
});
- it('should return empty string after split at the end', () => {
- assert.deepStrictEqual(splitByEmoji('helloπ'), [
- { type: 'text', value: 'hello' },
- { type: 'emoji', value: 'π' },
- { type: 'text', value: '' },
- ]);
- });
-
- it('should return empty string before the split at the start', () => {
- assert.deepStrictEqual(splitByEmoji('πhello'), [
- { type: 'text', value: '' },
- { type: 'emoji', value: 'π' },
- { type: 'text', value: 'hello' },
+ it('returns emojis as text after 5,000 emojis are found', () => {
+ assert.deepStrictEqual(splitByEmoji('π¬'.repeat(5002)), [
+ ...Array(5000).fill({ type: 'emoji', value: 'π¬' }),
+ { type: 'text', value: 'π¬π¬' },
]);
});
});
diff --git a/ts/util/emoji.ts b/ts/util/emoji.ts
index bf0d044370..b26c3ac349 100644
--- a/ts/util/emoji.ts
+++ b/ts/util/emoji.ts
@@ -4,8 +4,10 @@
import emojiRegex from 'emoji-regex/es2015/RGI_Emoji';
import { assert } from './assert';
+import { take } from './iterables';
const REGEXP = emojiRegex();
+const MAX_EMOJI_TO_MATCH = 5000;
export function replaceEmojiWithSpaces(value: string): string {
return value.replace(REGEXP, ' ');
@@ -17,19 +19,26 @@ export type SplitElement = Readonly<{
}>;
export function splitByEmoji(value: string): ReadonlyArray {
- const emojis = value.matchAll(REGEXP);
+ const emojis = take(value.matchAll(REGEXP), MAX_EMOJI_TO_MATCH);
const result: Array = [];
let lastIndex = 0;
for (const match of emojis) {
- result.push({ type: 'text', value: value.slice(lastIndex, match.index) });
+ const nonEmojiText = value.slice(lastIndex, match.index);
+ if (nonEmojiText) {
+ result.push({ type: 'text', value: nonEmojiText });
+ }
+
result.push({ type: 'emoji', value: match[0] });
assert(match.index !== undefined, '`matchAll` should provide indices');
lastIndex = match.index + match[0].length;
}
- result.push({ type: 'text', value: value.slice(lastIndex) });
+ const finalNonEmojiText = value.slice(lastIndex);
+ if (finalNonEmojiText) {
+ result.push({ type: 'text', value: finalNonEmojiText });
+ }
return result;
}