Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions app/containers/UIKit/__snapshots__/UiKitModal.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -829,9 +829,6 @@ exports[`Story Snapshots: ModalContextsDividers should match snapshot 1`] = `
"color": "#2F343D",
"lineHeight": undefined,
},
{
"color": "#6C727A",
},
]
}
testID="markdown-preview-Due today"
Expand Down Expand Up @@ -1818,9 +1815,6 @@ exports[`Story Snapshots: ModalFormTextArea should match snapshot 1`] = `
"color": "#2F343D",
"lineHeight": undefined,
},
{
"color": "#6C727A",
},
]
}
testID="markdown-preview-Task: ZOL-994"
Expand Down
12 changes: 3 additions & 9 deletions app/containers/UIKit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,17 @@ class MessageParser extends UiKitParserMessage<React.ReactElement> {

const isContext = context === BlockContext.CONTEXT;
if (isContext) {
return (
<MarkdownPreview msg={element.text} style={[isContext && { color: themes[theme].fontSecondaryInfo }]} numberOfLines={0} />
);
return <MarkdownPreview msg={element.text} numberOfLines={0} />;
}
return <Text style={[styles.text, { color: themes[theme].fontDefault }]}>{element.text}</Text>;
}

mrkdwn(element: IMarkdown, context: BlockContext) {
const { theme } = useContext(ThemeContext);

const isContext = context === BlockContext.CONTEXT;
if (isContext) {
return (
<MarkdownPreview msg={element.text} style={[isContext && { color: themes[theme].fontSecondaryInfo }]} numberOfLines={0} />
);
return <MarkdownPreview msg={element.text} numberOfLines={0} />;
}
return <Markdown msg={element.text} style={[isContext && { color: themes[theme].fontSecondaryInfo }]} />;
return <Markdown msg={element.text} />;
}
Comment on lines +72 to 75
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

numberOfLines={0} can be invalid in RN Text trees — confirm MarkdownPreview behavior

RN Text expects numberOfLines > 0; passing 0 may be ignored or cause issues if forwarded. If unlimited lines are desired, omit the prop.

Apply this minimal change if safe:

- return <MarkdownPreview msg={element.text} numberOfLines={0} />;
+ return <MarkdownPreview msg={element.text} />;

To check other occurrences:


🏁 Script executed:

#!/bin/bash
rg -n "MarkdownPreview.*numberOfLines=\{0\}"

Length of output: 323


🏁 Script executed:

#!/bin/bash
# Find the file(s) defining MarkdownPreview
rg -l "MarkdownPreview" -g "*.tsx" | grep -vE "index.tsx|Reply.tsx"

# Show definition and prop types
rg -n "MarkdownPreview" -C5 -g "*.tsx"

# Look for numberOfLines usage within its implementation
rg -n "numberOfLines" -C5 -g "*.tsx"

Length of output: 80723


Remove numberOfLines={0} from MarkdownPreview
Delete the prop in all instances to avoid passing 0 to RN Text, which hides content.
Occurrences:

  • app/containers/UIKit/index.tsx (plain_text at line 64, mrkdwn at line 72)
  • app/containers/message/Components/Attachments/Reply.tsx (line 139)
    Use <MarkdownPreview msg={…} /> instead.
🤖 Prompt for AI Agents
In app/containers/UIKit/index.tsx around lines 72–75 (and also check the
plain_text at ~line 64) and in
app/containers/message/Components/Attachments/Reply.tsx around line 139, remove
the prop numberOfLines={0} from all <MarkdownPreview> usages so RN Text isn’t
passed 0 which hides content; update each usage to call MarkdownPreview with
only the msg prop (i.e., remove the numberOfLines attribute).


button(element: IButton, context: BlockContext) {
Expand Down
5 changes: 1 addition & 4 deletions app/containers/markdown/Markdown.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,7 @@ export const Links = () => (
<Markdown msg='[Markdown link](https://rocket.chat): `[description](url)`' />
<Markdown msg='<https://rocket.chat|Formatted Link>: `<url|description>`' />
<Markdown msg='[Markdown link](https://rocket.chat) and the text with default style' />
<Markdown
msg='[Markdown link](https://rocket.chat) and the text with a color specific as fontSecondaryInfo'
style={[{ color: themes[theme].fontSecondaryInfo }]}
/>
<Markdown msg='[Markdown link](https://rocket.chat) and the text continues on the next line' />
</View>
);

Expand Down
4 changes: 2 additions & 2 deletions app/containers/markdown/__snapshots__/Markdown.test.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1586,7 +1586,7 @@ exports[`Story Snapshots: Links should match snapshot 1`] = `
Markdown link
</Text>
<Text
accessibilityLabel=" and the text with a color specific as fontSecondaryInfo"
accessibilityLabel=" and the text continues on the next line"
style={
[
{
Expand All @@ -1600,7 +1600,7 @@ exports[`Story Snapshots: Links should match snapshot 1`] = `
]
}
>
and the text with a color specific as fontSecondaryInfo
and the text continues on the next line
</Text>
</Text>
</Text>
Expand Down
9 changes: 1 addition & 8 deletions app/containers/markdown/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { type StyleProp, type TextStyle, View } from 'react-native';
import { View } from 'react-native';
import { parse } from '@rocket.chat/message-parser';
import type { Root } from '@rocket.chat/message-parser';
import isEmpty from 'lodash/isEmpty';
Expand Down Expand Up @@ -27,16 +27,9 @@ interface IMarkdownProps {
mentions?: IUserMention[];
getCustomEmoji?: TGetCustomEmoji;
username?: string;
tmid?: string;
numberOfLines?: number;
customEmojis?: boolean;
useRealName?: boolean;
channels?: IUserChannel[];
enableMessageParser?: boolean;
// TODO: Refactor when migrate Room
navToRoomInfo?: Function;
testID?: string;
style?: StyleProp<TextStyle>[];
Comment on lines -30 to -39
Copy link
Member Author

Choose a reason for hiding this comment

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

This is technically out of scope, but I found it and wanted to fix it 🙈
I can open as a separate PR, if you think it's too chaotic.

onLinkPress?: TOnLinkPress;
isTranslated?: boolean;
}
Expand Down
20 changes: 3 additions & 17 deletions app/containers/message/Components/Attachments/Attachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const removeQuote = (file?: IAttachment) =>
file?.image_url || file?.audio_url || file?.video_url || (file?.actions?.length || 0) > 0 || file?.collapsed;

const Attachments: React.FC<IMessageAttachments> = React.memo(
({ attachments, timeFormat, showAttachment, style, getCustomEmoji, isReply, author }: IMessageAttachments) => {
({ attachments, timeFormat, showAttachment, getCustomEmoji, author }: IMessageAttachments) => {
'use memo';

const { translateLanguage } = useContext(MessageContext);
Expand All @@ -26,7 +26,7 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
if (!nonQuoteAttachments || nonQuoteAttachments.length === 0) {
return null;
}
// TODO: memo?

const attachmentsElements = nonQuoteAttachments.map((file: IAttachment, index: number) => {
const msg = getMessageFromAttachment(file, translateLanguage);
if (file && file.image_url) {
Expand All @@ -36,8 +36,6 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
file={file}
showAttachment={showAttachment}
getCustomEmoji={getCustomEmoji}
style={style}
isReply={isReply}
author={author}
msg={msg}
imagePreview={file.image_preview}
Expand All @@ -47,17 +45,7 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
}

if (file && file.audio_url) {
return (
<Audio
key={file.audio_url}
file={file}
getCustomEmoji={getCustomEmoji}
isReply={isReply}
style={style}
author={author}
msg={msg}
/>
);
return <Audio key={file.audio_url} file={file} getCustomEmoji={getCustomEmoji} author={author} msg={msg} />;
}

if (file.video_url) {
Expand All @@ -67,8 +55,6 @@ const Attachments: React.FC<IMessageAttachments> = React.memo(
file={file}
showAttachment={showAttachment}
getCustomEmoji={getCustomEmoji}
style={style}
isReply={isReply}
author={author}
msg={msg}
/>
Expand Down
8 changes: 3 additions & 5 deletions app/containers/message/Components/Attachments/Audio.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useContext } from 'react';
import { type StyleProp, type TextStyle, View } from 'react-native';
import { View } from 'react-native';

import { type IAttachment, type IUserMessage } from '../../../../definitions';
import { type TGetCustomEmoji } from '../../../../definitions/IEmoji';
Expand All @@ -10,22 +10,20 @@ import { useMediaAutoDownload } from '../../hooks/useMediaAutoDownload';

interface IMessageAudioProps {
file: IAttachment;
isReply?: boolean;
style?: StyleProp<TextStyle>[];
getCustomEmoji: TGetCustomEmoji;
author?: IUserMessage;
msg?: string;
}

const MessageAudio = ({ file, getCustomEmoji, author, isReply, style, msg }: IMessageAudioProps) => {
const MessageAudio = ({ file, getCustomEmoji, author, msg }: IMessageAudioProps) => {
'use memo';

const { user, id, rid } = useContext(MessageContext);
const { status, onPress, url } = useMediaAutoDownload({ file, author });

return (
<View style={{ gap: 4 }}>
<Markdown msg={msg} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} />
{msg ? <Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} /> : null}
<AudioPlayer msgId={id} fileUri={url} downloadState={status} onPlayButtonPress={onPress} rid={rid} />
</View>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ const AttText = React.memo(
return null;
}

return <Markdown msg={text} username={user.username} getCustomEmoji={getCustomEmoji} style={[styles.fieldText]} />;
return <Markdown msg={text} username={user.username} getCustomEmoji={getCustomEmoji} />;
},
(prevProps, nextProps) => prevProps.text === nextProps.text
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ const ImageContainer = ({
file,
showAttachment,
getCustomEmoji,
style,
isReply,
author,
msg,
imagePreview,
Expand All @@ -36,7 +34,7 @@ const ImageContainer = ({
if (msg) {
return (
<View style={{ gap: 4 }}>
<Markdown msg={msg} style={[isReply && style]} username={user.username} getCustomEmoji={getCustomEmoji} />
<Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} />
{image}
</View>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { type StyleProp, type TextStyle } from 'react-native';

import { type IAttachment, type IUserMessage } from '../../../../../definitions';
import { type TGetCustomEmoji } from '../../../../../definitions/IEmoji';
import { type TDownloadState } from '../../../../../lib/methods/handleMediaDownload';

export interface IImageContainer {
file: IAttachment;
showAttachment?: (file: IAttachment) => void;
style?: StyleProp<TextStyle>[];
isReply?: boolean;
getCustomEmoji?: TGetCustomEmoji;
author?: IUserMessage;
msg?: string;
Expand Down
39 changes: 16 additions & 23 deletions app/containers/message/Components/Attachments/Reply.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import openLink from '../../../../lib/methods/helpers/openLink';
import { type TSupportedThemes, useTheme } from '../../../../theme';
import sharedStyles from '../../../../views/Styles';
import RCActivityIndicator from '../../../ActivityIndicator';
import Markdown from '../../../markdown';
import Markdown, { MarkdownPreview } from '../../../markdown';
import { Attachments } from './components';
import MessageContext from '../../Context';
import Touchable from '../../Touchable';
Expand Down Expand Up @@ -119,15 +119,7 @@ const Title = React.memo(
);

const Description = React.memo(
({
attachment,
getCustomEmoji,
theme
}: {
attachment: IAttachment;
getCustomEmoji: TGetCustomEmoji;
theme: TSupportedThemes;
}) => {
({ attachment, getCustomEmoji }: { attachment: IAttachment; getCustomEmoji: TGetCustomEmoji }) => {
'use memo';

const { user } = useContext(MessageContext);
Expand All @@ -137,14 +129,17 @@ const Description = React.memo(
return null;
}

return (
<Markdown
msg={text}
style={[{ color: themes[theme].fontHint, fontSize: 14 }]}
username={user.username}
getCustomEmoji={getCustomEmoji}
/>
);
// For file attachments without explicit text, the title is just a filename (e.g., "test.py").
// We use MarkdownPreview to avoid markdown parsing treating filenames as URLs or markdown syntax.
// For other attachments (message quotes, embeds), the text may contain actual markdown formatting,
// so we use the full Markdown component to preserve styling.
const isFileName = attachment.type === 'file' && !attachment.text;

if (isFileName) {
return <MarkdownPreview msg={text} numberOfLines={0} />;
}

return <Markdown msg={text} username={user.username} getCustomEmoji={getCustomEmoji} />;
},
(prevProps, nextProps) => {
if (prevProps.attachment.text !== nextProps.attachment.text) {
Expand All @@ -153,7 +148,7 @@ const Description = React.memo(
if (prevProps.attachment.title !== nextProps.attachment.title) {
return false;
}
if (prevProps.theme !== nextProps.theme) {
if (prevProps.attachment.type !== nextProps.attachment.type) {
return false;
}
return true;
Expand Down Expand Up @@ -257,13 +252,11 @@ const Reply = React.memo(
<View style={styles.attachmentContainer}>
<View style={styles.titleAndDescriptionContainer}>
<Title attachment={attachment} timeFormat={timeFormat} theme={theme} />
<Description attachment={attachment} getCustomEmoji={getCustomEmoji} theme={theme} />
<Description attachment={attachment} getCustomEmoji={getCustomEmoji} />
<Attachments
attachments={attachment.attachments}
getCustomEmoji={getCustomEmoji}
timeFormat={timeFormat}
style={[{ color: themes[theme].fontHint, fontSize: 14 }]}
isReply
showAttachment={showAttachment}
/>
<Fields attachment={attachment} getCustomEmoji={getCustomEmoji} theme={theme} />
Expand All @@ -281,7 +274,7 @@ const Reply = React.memo(
<UrlImage image={attachment.thumb_url} />
</View>
</Touchable>
<Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} />
{msg ? <Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} /> : null}
</View>
);
},
Expand Down
16 changes: 3 additions & 13 deletions app/containers/message/Components/Attachments/Video.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useContext } from 'react';
import { type StyleProp, StyleSheet, Text, type TextStyle, View } from 'react-native';
import { StyleSheet, Text, View } from 'react-native';

import { type IUserMessage } from '../../../../definitions';
import { type IAttachment } from '../../../../definitions/IAttachment';
Expand Down Expand Up @@ -39,8 +39,6 @@ interface IMessageVideo {
showAttachment?: (file: IAttachment) => void;
getCustomEmoji: TGetCustomEmoji;
author?: IUserMessage;
style?: StyleProp<TextStyle>[];
isReply?: boolean;
msg?: string;
}

Expand Down Expand Up @@ -72,15 +70,7 @@ const Thumbnail = ({ status, encrypted = false }: { status: TDownloadState; encr
);
};

const Video = ({
file,
showAttachment,
getCustomEmoji,
author,
style,
isReply,
msg
}: IMessageVideo): React.ReactElement | null => {
const Video = ({ file, showAttachment, getCustomEmoji, author, msg }: IMessageVideo): React.ReactElement | null => {
'use memo';

const { user } = useContext(MessageContext);
Expand Down Expand Up @@ -112,7 +102,7 @@ const Video = ({

return (
<View style={{ gap: 4 }}>
<Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} style={[isReply && style]} />
{msg ? <Markdown msg={msg} username={user.username} getCustomEmoji={getCustomEmoji} /> : null}
<Touchable onPress={_onPress} style={messageStyles.image} background={Touchable.Ripple(colors.surfaceNeutral)}>
<Thumbnail status={status} encrypted={isEncrypted} />
</Touchable>
Expand Down
3 changes: 0 additions & 3 deletions app/containers/message/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,13 @@ const Content = React.memo(
msg={props.msg}
md={props.type !== 'e2e' ? props.md : undefined}
getCustomEmoji={props.getCustomEmoji}
enableMessageParser={user.enableMessageParserEarlyAdoption}
username={user.username}
channels={props.channels}
mentions={props.mentions}
navToRoomInfo={props.navToRoomInfo}
tmid={props.tmid}
useRealName={props.useRealName}
onLinkPress={onLinkPress}
isTranslated={props.isTranslated}
testID={`message-markdown-${props.msg}`}
/>
);
}
Expand Down
Loading
Loading