Skip to content

Conversation

@Sumanth2377
Copy link

@Sumanth2377 Sumanth2377 commented Nov 24, 2025

Proposed changes

Refactored the Emoji component to be reusable across the application.

  • Created app/containers/Emoji/Emoji.tsx as a shared component.
  • Updated Markdown and EmojiPicker to use the new shared component.
  • This reduces code duplication and centralizes emoji rendering logic.

Issue(s)

Closes #6535

How to test or reproduce

  1. Open any chat room.
  2. Send a message with standard emojis (e.g., :smile:) and custom emojis.
  3. Verify that emojis render correctly in the message list (Markdown).
  4. Open the Emoji Picker.
  5. Verify that emojis render correctly in the picker list.

Screenshots

N/A (Refactor with no visual changes intended)

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Summary by CodeRabbit

  • New Features

    • Added a unified Emoji component with responsive sizing, avatar styling, and custom-emoji support; exposed as a public export.
  • Refactor

    • Standardized emoji rendering across picker, markdown, and UI by delegating to the shared Emoji implementation and simplifying local emoji logic.
    • Added a re-export to make the Emoji component available from the package module.
  • Tests

    • Added unit tests verifying standard and custom emoji rendering.

✏️ Tip: You can customize this high-level summary in your review settings.

@CLAassistant
Copy link

CLAassistant commented Nov 24, 2025

CLA assistant check
All committers have signed the CLA.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 24, 2025

Walkthrough

Adds a new reusable Emoji component and index re-export, updates EmojiPicker and Markdown emoji renderers to use the shared component, and adds unit tests covering both unicode and custom emoji rendering. Sizing and shortname-to-unicode conversion are centralized with fontScale-aware logic.

Changes

Cohort / File(s) Summary
New shared Emoji component
app/containers/Emoji/Emoji.tsx, app/containers/Emoji/index.ts
Adds default-exported Emoji functional component (literal, isBigEmoji, style, isAvatar, getCustomEmoji, customEmoji). Renders CustomEmoji when provided/resolved, otherwise converts shortname to unicode and renders Text. Uses theme colors and fontScale/fontScaleLimited sizing. Adds named re-export in index.ts.
EmojiPicker refactor
app/containers/EmojiPicker/Emoji.tsx
Replaces local emoji rendering with the shared Emoji component (../Emoji/Emoji); string emojis passed as literal=":{emoji}:", non-string as customEmoji={emoji}; removes prior local unicode/ascii/custom handling.
Markdown emoji refactor
app/containers/markdown/components/emoji/Emoji.tsx
Replaces in-file rendering with shared Emoji. Introduces getEmojiToken arrow helper to compute literal then delegates rendering. Removes local unicode conversion, CustomEmoji logic, and sizing/theme hooks; drops defaulted style/isAvatar in destructured props.
Tests
app/containers/Emoji/__tests__/Emoji.test.tsx
Adds tests that mock shortname-to-unicode hook, CustomEmoji, theme, and responsive layout. Covers standard emoji (:smile: → "😄") and custom emoji rendering paths.

Sequence Diagram(s)

sequenceDiagram
    participant Picker as EmojiPicker
    participant Markdown as MarkdownEmoji
    participant Shared as Emoji (shared)
    participant Custom as CustomEmoji
    participant Theme as ThemeProvider

    Picker->>Shared: render(literal=":{emoji}:" / customEmoji)
    Markdown->>Shared: render(literal from getEmojiToken(...))

    alt customEmoji provided or resolved
        Shared->>Custom: render(customEmoji, size = isBig ? big*fontScale : small*fontScale)
    else
        Shared->>Shared: formatShortnameToUnicode(literal) → unicode
        Shared->>Theme: read colors & fontScale/fontScaleLimited
        Shared->>Shared: render Unicode text (apply big/avatar styles)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Review focus:
    • app/containers/Emoji/Emoji.tsx — branching for customEmoji vs literal, fontScale and fontScaleLimited sizing math, theme color usage, and accessibility/testIDs.
    • app/containers/EmojiPicker/Emoji.tsx & app/containers/markdown/components/emoji/Emoji.tsx — confirm literal/token mapping preserves prior behavior.
    • app/containers/Emoji/__tests__/Emoji.test.tsx — ensure mocks align with real hooks/components and that tests cover both render paths.

Poem

A rabbit hops in code so spry, 🐇
I stitch a smile from shortname sky,
Picker and Markdown now agree,
One shared emoji for all to see,
I nibble bugs and bounce with glee. ✨

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: creating a reusable emoji component, which aligns with the primary objective and changeset.
Linked Issues check ✅ Passed All coding requirements from issue #6535 are met: a reusable Emoji component was created, and it's used in both Markdown rendering and EmojiPicker.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the stated objectives; no out-of-scope modifications were introduced beyond the emoji component refactoring.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
app/containers/Emoji/Emoji.tsx (1)

27-57: Optional: deduplicate custom emoji sizing logic

The size objects for customEmoji and foundCustomEmoji branches are identical. You can DRY this up for readability:

-    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} />;
-    }
+    const customEmojiSize = {
+        width: 15 * fontScale,
+        height: 15 * fontScale
+    };
+    const customEmojiBigSize = {
+        width: 30 * fontScale,
+        height: 30 * fontScale
+    };
+
+    if (customEmoji) {
+        return <CustomEmoji style={[isBigEmoji ? customEmojiBigSize : customEmojiSize, style]} emoji={customEmoji} />;
+    }-    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} />;
-    }
+    if (foundCustomEmoji) {
+        return <CustomEmoji style={[isBigEmoji ? customEmojiBigSize : customEmojiSize, style]} emoji={foundCustomEmoji} />;
+    }

This keeps the behavior identical while simplifying the component.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3532447 and 6128b2b.

📒 Files selected for processing (4)
  • app/containers/Emoji/Emoji.tsx (1 hunks)
  • app/containers/Emoji/index.ts (1 hunks)
  • app/containers/EmojiPicker/Emoji.tsx (1 hunks)
  • app/containers/markdown/components/emoji/Emoji.tsx (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
app/containers/EmojiPicker/Emoji.tsx (1)
app/containers/EmojiPicker/interfaces.ts (1)
  • IEmojiProps (44-46)
app/containers/markdown/components/emoji/Emoji.tsx (4)
app/containers/EmojiPicker/Emoji.tsx (1)
  • Emoji (7-12)
app/containers/markdown/Markdown.stories.tsx (1)
  • Emoji (94-101)
app/containers/markdown/components/emoji/index.ts (1)
  • Emoji (4-4)
app/containers/EmojiPicker/interfaces.ts (1)
  • IEmojiProps (44-46)
🪛 ESLint
app/containers/markdown/components/emoji/Emoji.tsx

[error] 25-25: 'index' is defined but never used. Allowed unused args must match /^_/u.

(@typescript-eslint/no-unused-vars)

app/containers/Emoji/Emoji.tsx

[error] 2-2: Imports "StyleProp" and "TextStyle" are only used as type.

(@typescript-eslint/consistent-type-imports)


[error] 25-25: 'convertAsciiEmoji' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🔇 Additional comments (3)
app/containers/Emoji/index.ts (1)

1-1: Barrel export looks good

Re-exporting the default Emoji as a named export is clean and keeps import sites consistent.

app/containers/EmojiPicker/Emoji.tsx (1)

5-11: Confirm expected shape of emoji string for picker items

Here you assume string emojis are shortcodes without colons and wrap them as :${emoji}:. If any caller already passes a colon-wrapped shortcode (e.g. :smile:), this would produce ::smile:: and fail lookup/conversion. Please double‑check the upstream IEmoji string representation for picker items and adjust (or guard) if mixed formats are possible.

app/containers/markdown/components/emoji/Emoji.tsx (1)

15-30: Clean up unused index prop in component signature

index is part of IEmojiProps (line 11 of the interface) but not used inside the component, causing the @typescript-eslint/no-unused-vars warning. Removing it from the destructuring while keeping it in the interface is the correct approach:

-const Emoji = ({ block, isBigEmoji, style, index, isAvatar }: IEmojiProps) => {
+const Emoji = ({ block, isBigEmoji, style, isAvatar }: IEmojiProps) => {

Call sites can still pass index, but the linter will no longer complain about the unused variable.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
app/containers/Emoji/Emoji.tsx (1)

26-26: Remove unused convertAsciiEmoji selector.

This variable is declared but never used in the component. The past review already flagged this issue, and it remains unresolved.

-    const convertAsciiEmoji = useAppSelector(state => getUserSelector(state)?.settings?.preferences?.convertAsciiEmoji);
🧹 Nitpick comments (2)
app/containers/Emoji/Emoji.tsx (2)

17-18: Consider stronger typing for custom emoji properties.

The any types for getCustomEmoji return value and customEmoji reduce type safety. Consider using a more specific type based on the CustomEmoji model from app/lib/database/model/CustomEmoji.js or defining a shared interface.

For example:

import type { CustomEmoji } from '../../lib/database/model/CustomEmoji';

interface ISharedEmojiProps {
    // ...
    getCustomEmoji?: (name: string) => CustomEmoji | undefined;
    customEmoji?: CustomEmoji;
}

21-83: Consider extracting magic numbers to named constants.

The component uses several magic numbers for sizing (15, 30 for emoji dimensions; 16, 22, 30, 43 for font sizes and line heights). Extracting these to named constants would improve code maintainability and make the sizing intent more explicit.

For example:

const EMOJI_SIZE = {
    SMALL: 15,
    BIG: 30
};

const TEXT_STYLE = {
    SMALL: { fontSize: 16, lineHeight: 22 },
    BIG: { fontSize: 30, lineHeight: 43 }
};

Then use these constants throughout the component instead of literal numbers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6128b2b and 29d5c00.

📒 Files selected for processing (1)
  • app/containers/Emoji/Emoji.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/containers/Emoji/Emoji.tsx (7)
app/containers/EmojiPicker/Emoji.tsx (1)
  • Emoji (7-12)
app/theme.tsx (1)
  • useTheme (29-29)
app/lib/hooks/useResponsiveLayout/useResponsiveLayout.tsx (1)
  • useResponsiveLayout (41-45)
app/lib/hooks/useAppSelector.ts (1)
  • useAppSelector (6-6)
app/selectors/login.ts (1)
  • getUserSelector (20-20)
app/lib/database/model/CustomEmoji.js (1)
  • CustomEmoji (8-18)
app/lib/constants/colors.ts (1)
  • colors (280-302)
🪛 ESLint
app/containers/Emoji/Emoji.tsx

[error] 26-26: 'convertAsciiEmoji' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🔇 Additional comments (1)
app/containers/Emoji/Emoji.tsx (1)

2-3: Type-only imports correctly applied.

The type-only imports for StyleProp and TextStyle have been correctly implemented, resolving the previous ESLint warning.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
app/containers/Emoji/Emoji.tsx (1)

8-9: Remove unused convertAsciiEmoji selector and related imports

convertAsciiEmoji is selected from the store but never used, and the only consumers of useAppSelector / getUserSelector in this file are for that value. This will keep tripping @typescript-eslint/no-unused-vars and unused import rules; you can safely delete the selector line and the two imports.

-import { useAppSelector } from '../../lib/hooks/useAppSelector';
-import { getUserSelector } from '../../selectors/login';
@@
-    const convertAsciiEmoji = useAppSelector(state => getUserSelector(state)?.settings?.preferences?.convertAsciiEmoji);

ASCII emoji handling is already encapsulated in formatShortnameToUnicode, so behavior shouldn’t change. Based on static analysis hints and prior review…

Also applies to: 26-26

🧹 Nitpick comments (1)
app/containers/Emoji/Emoji.tsx (1)

12-19: Consider tightening customEmoji / getCustomEmoji typing

Right now both customEmoji and the return type of getCustomEmoji are any. If feasible, wiring these to a shared CustomEmoji type (e.g., the Watermelon CustomEmoji model or a dedicated ICustomEmoji interface) would give you better autocomplete and catch mismatches at compile time, especially as this component becomes the central emoji renderer.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 29d5c00 and ccfe315.

📒 Files selected for processing (1)
  • app/containers/Emoji/Emoji.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/containers/Emoji/Emoji.tsx (7)
app/containers/EmojiPicker/Emoji.tsx (1)
  • Emoji (7-12)
app/theme.tsx (1)
  • useTheme (29-29)
app/lib/hooks/useResponsiveLayout/useResponsiveLayout.tsx (1)
  • useResponsiveLayout (41-45)
app/lib/hooks/useAppSelector.ts (1)
  • useAppSelector (6-6)
app/selectors/login.ts (1)
  • getUserSelector (20-20)
app/lib/database/model/CustomEmoji.js (1)
  • CustomEmoji (8-18)
app/lib/constants/colors.ts (1)
  • colors (280-302)
🪛 ESLint
app/containers/Emoji/Emoji.tsx

[error] 26-26: 'convertAsciiEmoji' is assigned a value but never used.

(@typescript-eslint/no-unused-vars)

🔇 Additional comments (1)
app/containers/Emoji/Emoji.tsx (1)

21-71: Emoji rendering flow and sizing look consistent and reusable

The control flow (explicit customEmoji → literal-based lookup via getCustomEmoji → Unicode Text fallback) and the shared custom emoji size definitions align well with the PR goal of centralizing emoji rendering. The use of fontScale/fontScaleLimited and theme colors is coherent and should keep existing visuals stable while de-duplicating logic.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/containers/Emoji/__tests__/Emoji.test.tsx (1)

27-37: Emoji tests correctly cover main rendering paths

The tests validate both standard emoji rendering via literal and custom emoji rendering via customEmoji with appropriate mocks. If you expand behavior later, consider adding cases for isBigEmoji, isAvatar, and the getCustomEmoji(literal) path, but not required for this refactor.

app/containers/Emoji/Emoji.tsx (1)

12-19: Consider strengthening types for custom emoji props

getCustomEmoji and customEmoji are typed as any, which loses type safety for this shared component. If you have a shared type for custom emojis (e.g., the model behind CustomEmoji), consider wiring it in here for better tooling and safer refactors in callers.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ccfe315 and f7d04b0.

⛔ Files ignored due to path filters (1)
  • app/containers/markdown/__snapshots__/Markdown.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • app/containers/Emoji/Emoji.tsx (1 hunks)
  • app/containers/Emoji/__tests__/Emoji.test.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
app/containers/Emoji/Emoji.tsx (5)
app/containers/EmojiPicker/Emoji.tsx (1)
  • Emoji (7-12)
app/theme.tsx (1)
  • useTheme (29-29)
app/lib/hooks/useResponsiveLayout/useResponsiveLayout.tsx (1)
  • useResponsiveLayout (41-45)
app/lib/database/model/CustomEmoji.js (1)
  • CustomEmoji (8-18)
app/lib/constants/colors.ts (1)
  • colors (280-302)
🪛 ESLint
app/containers/Emoji/Emoji.tsx

[error] 8-8: 'useAppSelector' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 9-9: 'getUserSelector' is defined but never used.

(@typescript-eslint/no-unused-vars)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
app/containers/Emoji/Emoji.tsx (1)

10-16: Consider tightening style typing to avoid the ImageStyle cast

style is declared as StyleProp<TextStyle> but then cast to StyleProp<ImageStyle> when passed into CustomEmoji. This works at runtime, but it slightly undermines TypeScript’s guarantees and may be confusing to readers. If this component continues to serve both text and image use cases, consider either:

  • Splitting props (e.g., textStyle for the <Text> path and imageStyle for CustomEmoji), or
  • Using a more generic style type that doesn’t require the as StyleProp<ImageStyle> cast.

Not urgent, but it would make the API and intent clearer.

Also applies to: 36-49

app/containers/markdown/components/emoji/Emoji.tsx (1)

15-23: Validate getEmojiToken against all EmojiProps variants and add tests

getEmojiToken appears to cover unicode (unicode in block), avatar (using block.value?.value), and the shortCode/value fallback, but its correctness is tightly coupled to how @rocket.chat/message-parser structures EmojiProps. It would be good to:

  • Double‑check that these are all the relevant shapes for emoji tokens (unicode, custom with shortCode, custom without shortCode, avatar), and
  • Add unit tests (or story cases) for each to ensure the produced literal is always what SharedEmoji and formatShortnameToUnicode expect.

That should protect this refactor from subtle regressions if the parser evolves.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c190e40 and b7bcaf2.

📒 Files selected for processing (2)
  • app/containers/Emoji/Emoji.tsx (1 hunks)
  • app/containers/markdown/components/emoji/Emoji.tsx (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
app/containers/markdown/components/emoji/Emoji.tsx (4)
app/containers/EmojiPicker/Emoji.tsx (1)
  • Emoji (7-12)
app/containers/markdown/Markdown.stories.tsx (1)
  • Emoji (94-101)
app/containers/markdown/components/emoji/index.ts (1)
  • Emoji (4-4)
app/containers/EmojiPicker/interfaces.ts (1)
  • IEmojiProps (44-46)
app/containers/Emoji/Emoji.tsx (5)
app/containers/EmojiPicker/Emoji.tsx (1)
  • Emoji (7-12)
app/theme.tsx (1)
  • useTheme (29-29)
app/lib/hooks/useResponsiveLayout/useResponsiveLayout.tsx (1)
  • useResponsiveLayout (41-45)
app/lib/database/model/CustomEmoji.js (1)
  • CustomEmoji (8-18)
app/lib/constants/colors.ts (1)
  • colors (280-302)
🔇 Additional comments (2)
app/containers/Emoji/Emoji.tsx (1)

19-50: Shared Emoji rendering and sizing logic look solid

The control flow between customEmoji, literalemojiUnicode, and getCustomEmoji lookup is clear and null-safe, and the centralized customEmojiSize / customEmojiBigSize definitions keep sizing consistent across both direct and looked-up custom emojis. The use of fontScale vs fontScaleLimited for images vs text also aligns with the intent to respect accessibility scaling without duplicating logic elsewhere.

app/containers/markdown/components/emoji/Emoji.tsx (1)

25-30: Delegation to SharedEmoji keeps Markdown emoji rendering consistent

Wiring literal, isBigEmoji, style, isAvatar, and getCustomEmoji straight into SharedEmoji cleanly centralizes the rendering logic, so Markdown emojis now share the same sizing and custom-emoji behavior as the picker and other consumers. This matches the PR’s reuse objective without changing the public Markdown emoji API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

improvement: create reusable emoji component

2 participants