Skip to content

feat: add enhanced mentions#3189

Open
MartinCupela wants to merge 17 commits into
masterfrom
feat/enhanced-mentions
Open

feat: add enhanced mentions#3189
MartinCupela wants to merge 17 commits into
masterfrom
feat/enhanced-mentions

Conversation

@MartinCupela

@MartinCupela MartinCupela commented May 13, 2026

Copy link
Copy Markdown
Contributor

🎯 Goal

Depends on: GetStream/stream-chat-js#1743
Depends on: GetStream/stream-chat-js#1772

Closes REACT-979

This PR brings enhanced mentions support to stream-chat-react across both the composer UI and rendered message text.

It updates the @ suggestion flow to render a mixed mention set from stream-chat-js, including direct users, built-in mentions like @channel and @here, roles, and user groups. The suggestion list now uses dedicated row components for each mention type, keeps keyboard navigation working across non-user items, and preserves accessibility and i18n behavior for the mixed result set.

It also extends the message text rendering pipeline so enhanced mentions are highlighted the same way direct user mentions are. The renderText path now accepts additive mention metadata, routes all mention kinds through a unified mention renderer contract via node.mentionedEntity, and keeps backward compatibility for older user-only mention consumers through the deprecated node.mentionedUser alias and the existing renderText(text, mentioned_users, options) signature.

Finally, the PR adds focused regression coverage for render-text behavior, quoted-message rendering, backward-compatible plugin usage, email-like mention edge cases, and multi-word mention names.

Highlights

  • Render mixed @ suggestion results from stream-chat-js:
    • direct users
    • @channel
    • @here
    • roles
    • user groups
  • Add dedicated suggestion row components:
    • MentionItem
    • SpecialMentionItem
    • RoleItem
    • UserGroupItem
  • Reuse a shared suggestion-row primitive for non-user mention rows
  • Preserve UserItem backward compatibility for existing consumers
  • Update suggestion-list accessibility copy for mixed mention results
  • Keep keyboard navigation and Enter selection working for non-user mentions
  • Extend renderText to support additive mention metadata through options.messageMentionEntities
  • Highlight built-in, role, and user-group mentions in:
    • message text
    • quoted messages
  • Unify rendered mention nodes under mention + node.mentionedEntity
  • Keep backward compatibility for:
    • node.mentionedUser
    • mentionsMarkdownPlugin(UserResponse[])
    • renderText(text, mentioned_users, options)

Summary by CodeRabbit

  • New Features

    • Expanded mention support: channel, broadcast (@here), roles, and user-group mentions; richer suggestion rows with keyboard selection
    • New reusable list-item layout and improved mention suggestion components
    • Customizable avatar fallback icon and three new UI icons
  • Accessibility & Interaction

    • Improved mention parsing, focus/keyboard behavior, and mention click/hover interactions
  • Styling

    • Added inverse/dark button variant and updated suggestion list styles
  • Localization

    • Added mention-related and role-notification translations across locales

# Conflicts:
#	src/components/Message/__tests__/__snapshots__/MessageText.test.tsx.snap
#	src/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.ts
#	src/components/Message/renderText/renderText.tsx
@MartinCupela MartinCupela force-pushed the feat/enhanced-mentions branch from b154ab1 to 8bc5ceb Compare June 1, 2026 11:28
Comment thread src/components/TextareaComposer/SuggestionList/BroadcastMentionItem.tsx Outdated
Comment thread src/components/ListItemLayout/ListItemLayout.tsx Outdated
Comment thread src/components/TextareaComposer/SuggestionList/RoleItem.tsx Outdated
@MartinCupela MartinCupela force-pushed the feat/enhanced-mentions branch from f59965d to 70241a5 Compare June 1, 2026 15:41
@MartinCupela MartinCupela requested a review from oliverlaz June 1, 2026 15:43
# Conflicts:
#	src/components/Message/__tests__/__snapshots__/MessageText.test.tsx.snap
@coderabbitai

coderabbitai Bot commented Jun 3, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0d6c6248-b30b-4f6c-84bf-b604635a3696

📥 Commits

Reviewing files that changed from the base of the PR and between 601081d and b027efc.

📒 Files selected for processing (7)
  • src/components/Message/MessageText.tsx
  • src/components/Message/renderText/__tests__/renderText.test.tsx
  • src/components/Message/renderText/renderText.tsx
  • src/components/MessageComposer/__tests__/MessageInput.test.tsx
  • src/utils/__tests__/mentionCapabilities.test.ts
  • src/utils/index.ts
  • src/utils/mentionCapabilities.ts
✅ Files skipped from review due to trivial changes (1)
  • src/utils/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/components/Message/MessageText.tsx
  • src/components/Message/renderText/tests/renderText.test.tsx
  • src/components/Message/renderText/renderText.tsx

📝 Walkthrough

Walkthrough

This PR adds a polymorphic ListItemLayout and icons, generalizes mention parsing to multiple entity types with new mention entities and a lookup-driven plugin, updates renderText and Mention rendering, implements mention-specific suggestion rows (user, role, channel, here, user-group), wires them into composer suggestion flows, adds utilities and i18n entries, and updates tests and package/config.

Changes

ListItemLayout Component and Icon Infrastructure

Layer / File(s) Summary
Icon Exports
src/components/Icons/icons.tsx
Three new icons added: IconMegaphone, IconShield, IconUsers via createIcon with SVG paths.
ListItemLayout Component
src/components/ListItemLayout/ListItemLayout.tsx, src/components/ListItemLayout/__tests__/ListItemLayout.test.tsx
Polymorphic ListItemLayout component renders configurable root elements with optional leading/trailing icons/slots, selected/destructive modifiers, and nested ListItemLayoutContent. Tests cover default rendering, button type handling, icon/slot counts, and ContentSlot override.
ListItemLayout Styling & Exports
src/components/ListItemLayout/styling/*, src/components/ListItemLayout/index.ts, src/components/index.ts, src/styling/index.scss
SCSS for list-item layout added; barrel re-export and global Sass import wired.
Avatar FallbackIcon
src/components/Avatar/Avatar.tsx, src/components/Avatar/__tests__/Avatar.test.tsx
Avatar accepts optional FallbackIcon?: ComponentType<ComponentPropsWithoutRef<'svg'>>, defaults to IconUser, and renders it when no initials/image are present; tests added for custom fallback.
Button Theme-Inverse
src/components/Button/styling/Button.scss
New .str-chat__theme-inverse modifier overrides button CSS custom properties to use *-on-dark variants.

Mention System Refactor and Message Integration

Layer / File(s) Summary
Mention Entity Types & Helpers
src/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.ts
Adds RenderTextMentionEntity/metadata types and helpers to compute mention display texts and derive mention entities from message metadata.
Mentions Markdown Plugin Refactor
src/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.ts
Replaces users-only regex matching with a lookup-driven plugin supporting users, channels, here, roles, and user groups; sorts replacements by length and generalizes email split-node handling; API overloaded to accept either UserResponse[] or RenderTextMentionEntity[].
Mention Component Update
src/components/Message/renderText/componentRenderers/Mention.tsx
Mention component consumes node.mentionedEntity and sets data-mention-id/data-mention-type, with data-user-id only for user mentions; types updated for compatibility.
RenderText Options and Function
src/components/Message/renderText/renderText.tsx
RenderTextOptions extended with messageMentionEntities and channelCapabilities; exports RenderTextFunction; renderText converted to function form and constructs mention display set and plugin from entities; email/link rewriting checks mention display set to avoid mis-parsing email-like tokens.
Message Text & Quoted Integration
src/components/Message/MessageText.tsx, src/components/MessageComposer/QuotedMessagePreview.tsx
MessageText and QuotedMessagePreview compute mention entities from message fields and pass them into renderText (with channel capability gating); interaction enabling uses computed entities.
Types & Context
src/components/Message/types.ts, src/context/MessageContext.tsx
MessageProps['renderText'] and MessageContextValue.renderText updated to use shared RenderTextFunction type.
RenderText Tests
src/components/Message/renderText/__tests__/renderText.test.tsx
Tests expanded to cover role/user-group mentions, email-pattern cases, multi-word exact matching, backward compatibility, and updated data-mention-* attributes.
Message Tests
src/components/Message/__tests__/*
Added/updated tests validating mention rendering, mention-type attributes, focus/tabindex behavior, and that mention handlers receive the message object.

Suggestion List Component Refactoring

Layer / File(s) Summary
Mention Item Base Types
src/components/TextareaComposer/SuggestionList/MentionItem/types.ts
Adds MentionItemComponentProps<TEntity> generic for mention item components.
TokenizedSuggestionParts
src/components/TextareaComposer/SuggestionList/TokenizedSuggestionParts.tsx, __tests__
New component rendering tokenized parts with matched class and normalizing boundary whitespace to non-breaking spaces; tests added.
MentionSuggestionTitle
src/components/TextareaComposer/SuggestionList/MentionItem/MentionSuggestionTitle.tsx
Small presentational component that prefixes children with @.
Mention Item Components & Dispatcher
src/components/TextareaComposer/SuggestionList/MentionItem/{UserItem,BroadcastMentionItem,RoleItem,UserGroupItem,SpecialMentionItem,MakeIndex,MentionItem}.tsx
New mention item modules render per-type rows (Avatar for user, IconMegaphone for channel/here, IconShield for roles, IconUsers for user-groups); MentionItem dispatches by mentionType and supports overrides; barrel export added.
SuggestionList Integration
src/components/TextareaComposer/SuggestionList/SuggestionList.tsx, SuggestionListItem.tsx, index.ts
SuggestionList now uses MentionItem for @ trigger; aria label updated to aria/Mention Suggestions; types and barrel exports updated (UserItem removed, new modules exported).
Suggestion Styling
src/components/TextareaComposer/styling/SuggestionList.scss
Adds mention-specific layout, leading-icon styling, typography, and truncation rules.
TextareaComposer Keyboard Fixes & tests
src/components/TextareaComposer/TextareaComposer.tsx, src/components/MessageComposer/__tests__/MessageInput.test.tsx, src/components/TextareaComposer/__tests__/MentionItem.test.tsx
Enter selects only when a focused item exists, ArrowDown wraps by loaded items length, focused index clamped; tests for mixed suggestions, keyboard selection of non-user mentions, and comprehensive MentionItem behavior added.

Internationalization, Utilities, and Packaging

Layer / File(s) Summary
i18n Mention Keys
src/i18n/{de,en,es,fr,hi,it,ja,ko,nl,pt,ru,tr}.json
Added aria/Mention Suggestions, mention/Channel*, mention/Here*, and Notify all {{ role }} members to locales; adjusted aria/User Suggestions entries across locales.
Mention Capabilities Utilities
src/utils/mentionCapabilities.ts, src/utils/index.ts, src/utils/__tests__/mentionCapabilities.test.ts
Adds MENTION_TYPE_CAPABILITY mapping, isMentionTypeAllowedByChannelCapabilities, and filterRenderTextMentionEntitiesByChannelCapabilities; barrel re-export and tests added.
Config & Package
.yarnrc.yml, package.json, examples/*/package.json
Adds npmPreapprovedPackages: [stream-chat], bumps stream-chat to ^9.45.0 in package files.
Styling imports
src/styling/index.scss, src/components/ListItemLayout/styling/index.scss
Adds @use imports to include ListItemLayout styles.

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 I hopped through code with tiny paws,

New mentions learned a dozen laws.
Icons, lists, and tokens spun —
Now channels, roles, groups join the fun.
A megaphone, shield, and friendly users too —
Hooray for mentions, fresh and new!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/enhanced-mentions

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/Message/MessageText.tsx (1)

81-83: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Gate mention keyboard interaction on all rendered mention entities, not just users.

renderTextMentionEntities now includes channel/here/role/user-group mentions, but isMentionsInteractionEnabled still keys off message.mentioned_users only. A message that contains only @channel, @here, a role, or a user group will render mention spans, yet the inner wrapper stays unfocusable and Enter/Space never reaches onMentionsClickMessage.

Suggested change
-  const hasMentionedUsers = Boolean(message.mentioned_users?.length);
+  const hasMentions = renderTextMentionEntities.length > 0;
   const isMentionsInteractionEnabled =
-    hasMentionedUsers && typeof onMentionsClickMessage === 'function';
+    hasMentions && typeof onMentionsClickMessage === 'function';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Message/MessageText.tsx` around lines 81 - 83, The
keyboard-interaction gating currently uses hasMentionedUsers and thus misses
non-user mentions; replace that check with a broader detection (e.g.,
hasMentionEntities) that returns true when any mention entity arrays exist or
when renderTextMentionEntities would produce mention spans — check fields like
message.mentioned_users, message.mentioned_roles, message.mentioned_groups,
message.mentioned_channels, and any "everyone"/"here"/"channel" indicator (or
fallback to examining the rendered entities output) and use that in
isMentionsInteractionEnabled alongside typeof onMentionsClickMessage to ensure
Enter/Space are focusable and routed to onMentionsClickMessage for all mention
types referenced by renderTextMentionEntities.
🧹 Nitpick comments (5)
src/components/TextareaComposer/SuggestionList/MentionItem/UserGroupItem.tsx (1)

17-17: ⚡ Quick win

Remove unnecessary void statement.

The void focused; statement appears to be dead code since focused is actually used on line 34 (selected={focused}). This statement serves no purpose and should be removed for clarity.

♻️ Proposed fix
   ...buttonProps
 }: UserGroupItemProps) => {
-  void focused;
-
   return (
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/TextareaComposer/SuggestionList/MentionItem/UserGroupItem.tsx`
at line 17, Remove the stray "void focused;" dead statement in
UserGroupItem.tsx; the variable focused is actually used later (e.g., passed to
selected={focused}) so simply delete that line to avoid the no-op and keep the
code clear while leaving the focused variable usage intact.
src/components/TextareaComposer/SuggestionList/TokenizedSuggestionParts.tsx (1)

13-31: ⚡ Quick win

Consider memoizing this component for better autocomplete performance.

TokenizedSuggestionParts will re-render whenever its parent suggestion item re-renders during autocomplete typing. Since this is in the hot path of the suggestion dropdown, wrapping it with React.memo would prevent unnecessary re-renders when tokenizedDisplayName hasn't changed.

♻️ Suggested memoization
-export const TokenizedSuggestionParts = ({
+export const TokenizedSuggestionParts = React.memo(({
   tokenizedDisplayName,
-}: TokenizedSuggestionPartsProps) =>
+}: TokenizedSuggestionPartsProps) => {
+  return (
+    <>
+      {tokenizedDisplayName.parts.map((part, i) => {
-  tokenizedDisplayName.parts.map((part, i) => {
     const matches = part.toLowerCase() === tokenizedDisplayName.token;
     const partWithHTMLSpacesAround = part.replace(/^\s+|\s+$/g, '\u00A0');

     return (
       <span
         className={clsx({
           'str-chat__emoji-item-part': !matches,
           'str-chat__suggestion-item-part--match': matches,
         })}
         key={`part-${i}`}
       >
         {partWithHTMLSpacesAround}
       </span>
     );
-  });
+      })}
+    </>
+  );
+});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/TextareaComposer/SuggestionList/TokenizedSuggestionParts.tsx`
around lines 13 - 31, Wrap the TokenizedSuggestionParts functional component
with React.memo so it only re-renders when its props change; specifically
memoize the exported TokenizedSuggestionParts (which takes tokenizedDisplayName:
TokenizedSuggestionPartsProps) to avoid re-rendering on parent updates during
autocomplete and ensure the memo key uses the default shallow prop comparison
(or provide a custom comparison that deeply compares tokenizedDisplayName if
necessary).
src/components/MessageComposer/__tests__/MessageInput.test.tsx (1)

1311-1379: ⚡ Quick win

Cover the actual wraparound branch.

This test sets hasNext: true, but it never moves past the last loaded suggestion, so it does not exercise the new nextIndex >= loadedItems.length path in src/components/TextareaComposer/TextareaComposer.tsx Line 209. Add one more ArrowDown from @here and assert that selection wraps back to @channel; otherwise the changed boundary behavior can regress unnoticed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/MessageComposer/__tests__/MessageInput.test.tsx` around lines
1311 - 1379, Test does not exercise the wraparound branch (nextIndex >=
loadedItems.length) in TextareaComposer.tsx; update the MessageInput.test.tsx
test so after selecting '`@here`' you fire one more ArrowDown key event to move
past the last loaded suggestion, then assert the selection wraps to '`@channel`'
(e.g., fire another fireEvent.keyDown(formElement, { key: 'ArrowDown' }) before
confirming with Enter and expect formElement toHaveValue('`@channel` ')).
Reference the suggestions/searchSource usage in this test and the nextIndex >=
loadedItems.length behavior in TextareaComposer.tsx when adding the extra
ArrowDown + assertion.
src/components/MessageComposer/QuotedMessagePreview.tsx (1)

409-411: 💤 Low value

Consider removing redundant mentioned_users parameter.

The renderText call passes both quotedMessage?.mentioned_users (deprecated parameter) and messageMentionEntities: quotedMessageMentionEntities (new option), where quotedMessageMentionEntities already includes the mentioned users. Since renderText derives entities from messageMentionEntities when present (line 149-151 in renderText.tsx), the deprecated parameter is unused here.

♻️ Simplify by removing redundant parameter
-      renderedText = renderText(quotedMessageText, quotedMessage?.mentioned_users, {
+      renderedText = renderText(quotedMessageText, undefined, {
         messageMentionEntities: quotedMessageMentionEntities,
       });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/MessageComposer/QuotedMessagePreview.tsx` around lines 409 -
411, The renderText call is passing a deprecated second argument
quotedMessage?.mentioned_users while also supplying messageMentionEntities:
quotedMessageMentionEntities in the options; because renderText prefers
messageMentionEntities (see renderText), remove the redundant
quotedMessage?.mentioned_users argument from the renderedText invocation and
rely solely on the options object (messageMentionEntities:
quotedMessageMentionEntities) so entities are derived from
quotedMessageMentionEntities; update the call site in QuotedMessagePreview.tsx
where renderedText = renderText(quotedMessageText,
quotedMessage?.mentioned_users, { messageMentionEntities:
quotedMessageMentionEntities }) to the single-argument form using the options
object.
src/components/Message/types.ts (1)

73-74: ⚡ Quick win

Update the renderText prop docs to match the new contract.

This prop now exposes RenderTextFunction, but the JSDoc still points to the old utils location and doesn't mention the new options.messageMentionEntities path or the deprecated mentionedUsers argument. Please refresh the inline docs here, and any matching guide page if this prop is documented externally. As per coding guidelines, src/**/*.{ts,tsx}: Ensure public API changes include documentation updates.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/Message/types.ts` around lines 73 - 74, Update the JSDoc for
the renderText?: RenderTextFunction prop to reflect the new contract: remove the
old utils link, describe that the function receives (text, options) where
mention data is now available at options.messageMentionEntities (and note the
mentionedUsers argument is deprecated), and briefly document expected return
values/behavior; update any matching external docs or guide pages that reference
the old signature to use RenderTextFunction and the new
options.messageMentionEntities path.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/Avatar/__tests__/Avatar.test.tsx`:
- Around line 69-74: The test in Avatar.test.tsx expects the wrong CSS class for
custom fallback icons; update the assertion in the 'should render a custom
fallback icon when provided and no initials are available' case to look for the
class produced by createIcon (use 'str-chaticon--megaphone' for IconMegaphone)
instead of '.str-chat__icon--megaphone' so the check on the rendered Avatar (use
AVATAR_ROOT_TEST_ID and the FallbackIcon=IconMegaphone usage) matches the
createIcon naming convention.

In `@src/components/ListItemLayout/styling/ListItemLayout.scss`:
- Around line 3-10: The stylesheet is failing stylelint's
declaration-empty-line-before rule for the custom property and the later
declarations; add a blank line immediately before the flagged declarations to
satisfy the rule. Specifically, insert an empty line before the
--list-item-padding declaration in the .str-chat__list-item-layout selector and
likewise add an empty line before the other flagged declaration(s) (e.g., the
padding declaration around the same selector or at the later block near lines
38–40) so the rule no longer reports errors.

In `@src/components/Message/__tests__/MessageText.test.tsx`:
- Around line 377-405: Add assertions to the existing test ("renders built-in,
role, and user-group mentions with mention styling") to verify keyboard
accessibility: for each mention found via getByText('`@channel`'),
getByText('`@here`'), getByText('`@admin`'), and getByText('`@Backend` Team') locate
the surrounding mention wrapper (e.g.,
element.closest('.str-chat__message-mention') or the element returned by
renderMessageText) and assert it is focusable by checking it has tabindex="0"
(or element.tabIndex === 0); ensure these extra expect checks are added after
the current attribute assertions and before the axe accessibility check so the
regression for focus/Enter on non-user mentions is covered.

In `@src/components/Message/MessageText.tsx`:
- Around line 55-57: In MessageText.tsx, replace the incorrect use of
message.mentioned_groups with message.mentioned_group_ids when calling
getRenderTextMentionEntities and update the helper/types used by
getRenderTextMentionEntities to accept mentioned_group_ids (or map
mentioned_group_ids -> expected shape) so TypeScript no longer reports TS2551;
also ensure isMentionsInteractionEnabled’s gating logic is updated so mention
interaction is enabled for group mentions (not just mentioned_users) when those
entities are rendered.

In `@src/components/TextareaComposer/styling/SuggestionList.scss`:
- Around line 42-60: The SCSS violates stylelint's declaration-empty-line-before
rule: in .str-chat__suggestion-list__item-title and
.str-chat__suggestion-list__item-details, add a blank line before any property
declaration that immediately follows an `@include` (i.e., ensure there is an empty
line between the `@include` utils.ellipsis-text; and the next declaration such as
text-align: start; or color: ...), so update those selectors (and similarly
.str-chat__list-item-layout__title.str-chat__suggestion-list__mention-item-title
if needed) to insert the required empty lines after mixins to satisfy linting.

In `@src/components/TextareaComposer/SuggestionList/SuggestionList.tsx`:
- Around line 223-235: The current compatibility check uses the translated
string value via legacyUserSuggestionsLabel which relies on locale bundles;
instead update the mentions branch in the suggestionMenuLabel computation to
resolve the new key with the old key as a fallback by calling t('aria/Mention
Suggestions', { defaultValue: t('aria/User Suggestions') }), remove the runtime
comparison to legacyUserSuggestionsLabel, and keep the other branches that use
t('aria/Command Suggestions') and t('aria/Emoji Suggestions') unchanged so
suggestions.searchSource.type still drives selection.

In `@src/i18n/ja.json`:
- Line 144: Replace the English value for the JSON key "aria/User Suggestions"
with the correct Japanese translation (e.g., "ユーザー候補") so the value is in
Japanese (not "aria/User Suggestions"); update the entry for "aria/User
Suggestions" in the ja.json translations and then run yarn validate-translations
to ensure the file passes validation.

In `@src/i18n/ko.json`:
- Line 144: The translation for the JSON key "aria/User Suggestions" currently
uses the English key as its value; update the value to the correct Korean
translation (e.g., "사용자 제안") for the key "aria/User Suggestions" in
src/i18n/ko.json, ensure the value is a non-empty Korean string consistent with
other aria entries (see "aria/Mention Suggestions"), and run yarn
validate-translations after the change.

In `@src/i18n/nl.json`:
- Line 145: The JSON entry for the translation key "aria/User Suggestions"
currently uses the English key as its value; replace that value with the correct
Dutch translation (e.g., "Gebruikerssuggesties") for the "aria/User Suggestions"
key in the nl.json translations so Dutch users see localized text, then run yarn
validate-translations to ensure all translations are valid.

In `@src/i18n/pt.json`:
- Line 153: Update the translation value for the JSON key "aria/User
Suggestions" so it is a Portuguese string (e.g., "Sugestões de usuários")
instead of the English key; locate the "aria/User Suggestions" entry in the
pt.json translations and replace the value with the correct Portuguese
translation, ensure the string is non-empty and matches style of other entries
like "aria/Mention Suggestions", then run `yarn validate-translations` to
confirm no validation errors.

In `@src/i18n/ru.json`:
- Line 162: The JSON key "aria/User Suggestions" has an untranslated value;
update its value to the correct Russian string (e.g., the localized aria label
for "User Suggestions") in the ru.json entry for "aria/User Suggestions", then
search other src/i18n/*.json files for any identical untranslated key/value
pairs and correct them as needed; finally run yarn validate-translations to
ensure all locale files pass validation.

---

Outside diff comments:
In `@src/components/Message/MessageText.tsx`:
- Around line 81-83: The keyboard-interaction gating currently uses
hasMentionedUsers and thus misses non-user mentions; replace that check with a
broader detection (e.g., hasMentionEntities) that returns true when any mention
entity arrays exist or when renderTextMentionEntities would produce mention
spans — check fields like message.mentioned_users, message.mentioned_roles,
message.mentioned_groups, message.mentioned_channels, and any
"everyone"/"here"/"channel" indicator (or fallback to examining the rendered
entities output) and use that in isMentionsInteractionEnabled alongside typeof
onMentionsClickMessage to ensure Enter/Space are focusable and routed to
onMentionsClickMessage for all mention types referenced by
renderTextMentionEntities.

---

Nitpick comments:
In `@src/components/Message/types.ts`:
- Around line 73-74: Update the JSDoc for the renderText?: RenderTextFunction
prop to reflect the new contract: remove the old utils link, describe that the
function receives (text, options) where mention data is now available at
options.messageMentionEntities (and note the mentionedUsers argument is
deprecated), and briefly document expected return values/behavior; update any
matching external docs or guide pages that reference the old signature to use
RenderTextFunction and the new options.messageMentionEntities path.

In `@src/components/MessageComposer/__tests__/MessageInput.test.tsx`:
- Around line 1311-1379: Test does not exercise the wraparound branch (nextIndex
>= loadedItems.length) in TextareaComposer.tsx; update the MessageInput.test.tsx
test so after selecting '`@here`' you fire one more ArrowDown key event to move
past the last loaded suggestion, then assert the selection wraps to '`@channel`'
(e.g., fire another fireEvent.keyDown(formElement, { key: 'ArrowDown' }) before
confirming with Enter and expect formElement toHaveValue('`@channel` ')).
Reference the suggestions/searchSource usage in this test and the nextIndex >=
loadedItems.length behavior in TextareaComposer.tsx when adding the extra
ArrowDown + assertion.

In `@src/components/MessageComposer/QuotedMessagePreview.tsx`:
- Around line 409-411: The renderText call is passing a deprecated second
argument quotedMessage?.mentioned_users while also supplying
messageMentionEntities: quotedMessageMentionEntities in the options; because
renderText prefers messageMentionEntities (see renderText), remove the redundant
quotedMessage?.mentioned_users argument from the renderedText invocation and
rely solely on the options object (messageMentionEntities:
quotedMessageMentionEntities) so entities are derived from
quotedMessageMentionEntities; update the call site in QuotedMessagePreview.tsx
where renderedText = renderText(quotedMessageText,
quotedMessage?.mentioned_users, { messageMentionEntities:
quotedMessageMentionEntities }) to the single-argument form using the options
object.

In
`@src/components/TextareaComposer/SuggestionList/MentionItem/UserGroupItem.tsx`:
- Line 17: Remove the stray "void focused;" dead statement in UserGroupItem.tsx;
the variable focused is actually used later (e.g., passed to selected={focused})
so simply delete that line to avoid the no-op and keep the code clear while
leaving the focused variable usage intact.

In `@src/components/TextareaComposer/SuggestionList/TokenizedSuggestionParts.tsx`:
- Around line 13-31: Wrap the TokenizedSuggestionParts functional component with
React.memo so it only re-renders when its props change; specifically memoize the
exported TokenizedSuggestionParts (which takes tokenizedDisplayName:
TokenizedSuggestionPartsProps) to avoid re-rendering on parent updates during
autocomplete and ensure the memo key uses the default shallow prop comparison
(or provide a custom comparison that deeply compares tokenizedDisplayName if
necessary).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aea911be-dcf9-4f80-a8da-7398c0d0a4b0

📥 Commits

Reviewing files that changed from the base of the PR and between 4c934ae and 6b507ce.

⛔ Files ignored due to path filters (1)
  • src/components/Message/renderText/__tests__/__snapshots__/renderText.test.tsx.snap is excluded by !**/*.snap
📒 Files selected for processing (51)
  • src/components/Avatar/Avatar.tsx
  • src/components/Avatar/__tests__/Avatar.test.tsx
  • src/components/Button/styling/Button.scss
  • src/components/Icons/icons.tsx
  • src/components/ListItemLayout/ListItemLayout.tsx
  • src/components/ListItemLayout/__tests__/ListItemLayout.test.tsx
  • src/components/ListItemLayout/index.ts
  • src/components/ListItemLayout/styling/ListItemLayout.scss
  • src/components/ListItemLayout/styling/index.scss
  • src/components/Message/MessageText.tsx
  • src/components/Message/__tests__/MessageText.test.tsx
  • src/components/Message/__tests__/QuotedMessage.test.tsx
  • src/components/Message/renderText/__tests__/renderText.test.tsx
  • src/components/Message/renderText/componentRenderers/Mention.tsx
  • src/components/Message/renderText/rehypePlugins/mentionsMarkdownPlugin.ts
  • src/components/Message/renderText/renderText.tsx
  • src/components/Message/types.ts
  • src/components/MessageComposer/QuotedMessagePreview.tsx
  • src/components/MessageComposer/__tests__/MessageInput.test.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/BroadcastMentionItem.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/MentionItem.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/MentionSuggestionTitle.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/RoleItem.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/SpecialMentionItem.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/UserGroupItem.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/UserItem.tsx
  • src/components/TextareaComposer/SuggestionList/MentionItem/index.ts
  • src/components/TextareaComposer/SuggestionList/MentionItem/types.ts
  • src/components/TextareaComposer/SuggestionList/SuggestionList.tsx
  • src/components/TextareaComposer/SuggestionList/SuggestionListItem.tsx
  • src/components/TextareaComposer/SuggestionList/TokenizedSuggestionParts.tsx
  • src/components/TextareaComposer/SuggestionList/UserItem.tsx
  • src/components/TextareaComposer/SuggestionList/index.ts
  • src/components/TextareaComposer/TextareaComposer.tsx
  • src/components/TextareaComposer/__tests__/MentionItem.test.tsx
  • src/components/TextareaComposer/styling/SuggestionList.scss
  • src/components/index.ts
  • src/context/MessageContext.tsx
  • src/i18n/de.json
  • src/i18n/en.json
  • src/i18n/es.json
  • src/i18n/fr.json
  • src/i18n/hi.json
  • src/i18n/it.json
  • src/i18n/ja.json
  • src/i18n/ko.json
  • src/i18n/nl.json
  • src/i18n/pt.json
  • src/i18n/ru.json
  • src/i18n/tr.json
  • src/styling/index.scss
💤 Files with no reviewable changes (1)
  • src/components/TextareaComposer/SuggestionList/UserItem.tsx

Comment thread src/components/Avatar/__tests__/Avatar.test.tsx
Comment thread src/components/ListItemLayout/styling/ListItemLayout.scss
Comment thread src/components/Message/__tests__/MessageText.test.tsx
Comment thread src/components/Message/MessageText.tsx
Comment thread src/components/TextareaComposer/styling/SuggestionList.scss
Comment thread src/i18n/ja.json Outdated
Comment thread src/i18n/ko.json Outdated
Comment thread src/i18n/nl.json Outdated
Comment thread src/i18n/pt.json Outdated
Comment thread src/i18n/ru.json Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Line 105: Update the unsatisfiable "stream-chat" version in package.json (both
the peerDependencies and devDependencies entries) to a published release (e.g.,
change "^9.45.0" to a known published version such as "^9.44.2"), then run
npm/yarn install to verify resolution and re-check that the chosen published
version contains the enhanced mentions API required by the dependent
stream-chat-js change; update both occurrences of the "stream-chat" dependency
to the same valid version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 96584f4f-5683-48f0-ab89-86029b2f3b5b

📥 Commits

Reviewing files that changed from the base of the PR and between 6b507ce and e9ca26f.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (2)
  • .yarnrc.yml
  • package.json

Comment thread package.json
"react": "^19.0.0 || ^18.0.0 || ^17.0.0",
"react-dom": "^19.0.0 || ^18.0.0 || ^17.0.0",
"stream-chat": "^9.44.2"
"stream-chat": "^9.45.0"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

stream-chat npm package version 9.45.0 release notes

💡 Result:

As of June 4, 2026, version 9.45.0 of the stream-chat npm package has not been released. The latest available versions in the stream-chat series are 9.44.0 through 9.44.2, which were published in May 2026 [1][2]. You can monitor the official GitHub repository for future release notes and version updates [3][4].

Citations:


Fix stream-chat dependency version: ^9.45.0 isn’t published.

In package.json (peerDependencies/devDependencies, lines 105 and 175), stream-chat is set to ^9.45.0, but the npm registry shows 9.45.0 has not been released (latest is 9.44.0–9.44.2). This will make the dependency unsatisfiable; update to a published version and then re-check whether it includes the enhanced mentions API from the dependent stream-chat-js PR.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 105, Update the unsatisfiable "stream-chat" version in
package.json (both the peerDependencies and devDependencies entries) to a
published release (e.g., change "^9.45.0" to a known published version such as
"^9.44.2"), then run npm/yarn install to verify resolution and re-check that the
chosen published version contains the enhanced mentions API required by the
dependent stream-chat-js change; update both occurrences of the "stream-chat"
dependency to the same valid version.

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

Size Change: +13.8 kB (+2.11%)

Total Size: 671 kB

📦 View Changed
Filename Size Change
dist/cjs/emojis.js 2.54 kB -1 B (-0.04%)
dist/cjs/index.js 259 kB +3.9 kB (+1.53%)
dist/cjs/ReactPlayerWrapper.js 546 B +1 B (+0.18%)
dist/cjs/useNotificationApi.js 52.6 kB +2.8 kB (+5.63%) 🔍
dist/css/index.css 40.3 kB +566 B (+1.42%)
dist/es/index.mjs 256 kB +3.84 kB (+1.52%)
dist/es/useNotificationApi.mjs 51.3 kB +2.73 kB (+5.63%) 🔍
ℹ️ View Unchanged
Filename Size
dist/cjs/audioProcessing.js 1.74 kB
dist/cjs/mp3-encoder.js 814 B
dist/css/emoji-picker.css 178 B
dist/css/emoji-replacement.css 456 B
dist/es/audioProcessing.mjs 1.65 kB
dist/es/emojis.mjs 2.47 kB
dist/es/mp3-encoder.mjs 768 B
dist/es/ReactPlayerWrapper.mjs 485 B

compressed-size-action

@codecov

codecov Bot commented Jun 5, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.64253% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 84.07%. Comparing base (4c057bb) to head (601081d).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
...rc/components/Channel/hooks/useMentionsHandlers.ts 77.77% 2 Missing ⚠️
...c/components/TextareaComposer/TextareaComposer.tsx 90.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #3189      +/-   ##
==========================================
+ Coverage   83.79%   84.07%   +0.28%     
==========================================
  Files         439      447       +8     
  Lines       13203    13366     +163     
  Branches     4280     4355      +75     
==========================================
+ Hits        11063    11238     +175     
+ Misses       2140     2128      -12     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

3 participants