Skip to content

MM-56577 Fixing font display issues on thread items#9630

Open
avasconcelos114 wants to merge 5 commits intomainfrom
MM-56577
Open

MM-56577 Fixing font display issues on thread items#9630
avasconcelos114 wants to merge 5 commits intomainfrom
MM-56577

Conversation

@avasconcelos114
Copy link
Copy Markdown
Contributor

Summary

This PR addresses issues with the styling of text as they appear in the thread list.

Also as brought up in the Jira ticket, I also made the changes needed in order to add extra spacing between the heading and body of the message if the heading is present while still keeping the total number of lines displayed at 2

Ticket Link

https://mattermost.atlassian.net/browse/MM-56577

Checklist

  • Added or updated unit tests (required for all new features)
  • Has UI changes
  • Have tested against the 5 core themes to ensure consistency between them.
  • Have run E2E tests by adding label E2E/Run (or E2E/Run-iOS / E2E/Run-Android for platform-specific runs).

Device Information

This PR was tested on:
iPhone 16 Pro (Simulator), iOS 18.3

Screenshots

before after
image image

Release Note

Fixed @mentions rendering incorrect font sizes when written as part of a heading in Threads screen

@avasconcelos114 avasconcelos114 self-assigned this Mar 25, 2026
@avasconcelos114 avasconcelos114 added 2: Dev Review Requires review by a core commiter 2: UX Review Requires review by a UX Designer labels Mar 25, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 25, 2026

📝 Walkthrough

Walkthrough

This change adds comprehensive test coverage for the RemoveMarkdown component and extends it with new numberOfLines and separateHeading props to handle separate heading block rendering with line limiting. Supporting style and type definitions are updated accordingly, and component usage is updated to leverage the new functionality.

Changes

Cohort / File(s) Summary
Component Implementation
app/components/remove_markdown/index.tsx
Extended RemoveMarkdown with numberOfLines and separateHeading props; added HeadingBlock logic to measure heading line counts via onTextLayout and conditionally apply wrapper styling; updated mention rendering to filter heading context before style computation; modified markdown renderer to conditionally handle headings and paragraphs separately.
Test Coverage
app/components/remove_markdown/index.test.tsx
Added comprehensive Jest test suite covering heading markdown stripping, heading levels 1–6, heading-mention interactions, line breaking on heading text, separate heading rendering when enabled, and basic text/mention/code span rendering.
Type & Style Definitions
types/global/markdown.ts, app/utils/markdown/index.ts
Extended MarkdownBlockStyles type with new required headingBlock: ViewStyle property; added corresponding headingBlock style rule with marginBottom: 8 to markdown stylesheet.
Component Usage
app/screens/global_threads/threads_list/thread/thread.tsx
Updated RemoveMarkdown rendering to pass numberOfLines={2} and separateHeading={true} props directly instead of wrapping in a Text component; increased message preview length from 100 to 150 characters.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

3: QA Review

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly relates to the main change: fixing font display issues in thread items, which is the core focus of the PR.
Description check ✅ Passed The description is related to the changeset, explaining the font styling fixes and spacing improvements for thread list items.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 MM-56577

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

Copy link
Copy Markdown
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.

🧹 Nitpick comments (2)
app/components/remove_markdown/index.tsx (1)

146-156: Clarify the first parameter semantics.

The first parameter is used to determine whether to render the paragraph, but its meaning isn't immediately clear. A brief comment would help future maintainers understand that this indicates whether it's the first paragraph following a heading (relevant for the two-line preview).

📝 Suggested documentation
-    const renderParagraph = useCallback(({children, first}: {children: ReactNode; first: boolean}) => {
+    // `first` indicates whether this is the first paragraph in the document,
+    // used to show only the first paragraph in thread previews
+    const renderParagraph = useCallback(({children, first}: {children: ReactNode; first: boolean}) => {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/remove_markdown/index.tsx` around lines 146 - 156, The
renderParagraph callback's boolean parameter first is unclear; add a short
inline comment above the renderParagraph definition explaining that first ===
true indicates the paragraph is the first paragraph after a heading (used to
decide rendering when separateHeading and a two-line preview via
numberOfLines/paragraphLines are in effect). Mention renderParagraph, first,
separateHeading, paragraphLines, numberOfLines and headingLineCount so
maintainers understand the interaction and why only the first paragraph may be
rendered.
app/components/remove_markdown/index.test.tsx (1)

126-158: Consider strengthening the separateHeading test assertion.

The test at lines 144-157 only verifies that "Heading" and "Body" strings exist in the JSON output, but doesn't actually verify that the heading is rendered in a View block as the test name suggests. Consider checking for structural elements or using a more specific assertion.

💡 Proposed enhancement for more robust assertion
         it('should render heading in a View block when separateHeading is set', () => {
             const {toJSON} = renderWithIntl(
                 <RemoveMarkdown
                     baseStyle={baseStyle}
                     numberOfLines={2}
                     separateHeading={true}
                     value={'### Heading\nBody text'}
                 />,
             );

             const json = JSON.stringify(toJSON());
             expect(json).toContain('Heading');
             expect(json).toContain('Body');
+            // Verify View wrapper exists at root level
+            const tree = toJSON();
+            expect(tree?.type).toBe('View');
         });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/remove_markdown/index.test.tsx` around lines 126 - 158, The
test for separateHeading is too weak: it only checks that "Heading" and "Body"
strings exist but not that the heading is rendered inside a View as intended;
update the test for RemoveMarkdown (test suite 'heading block separation') to
inspect the rendered tree structure (via toJSON() or the render wrapper APIs)
and assert that there is a node with type 'View' (or component name used by
RemoveMarkdown for heading blocks) whose children/text equals the heading
content, while the body remains in a separate node — locate the assertion around
the second it('should render heading in a View block when separateHeading is
set') and replace or extend the contains checks with a structural assertion that
the heading node is wrapped by a View node.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@app/components/remove_markdown/index.test.tsx`:
- Around line 126-158: The test for separateHeading is too weak: it only checks
that "Heading" and "Body" strings exist but not that the heading is rendered
inside a View as intended; update the test for RemoveMarkdown (test suite
'heading block separation') to inspect the rendered tree structure (via toJSON()
or the render wrapper APIs) and assert that there is a node with type 'View' (or
component name used by RemoveMarkdown for heading blocks) whose children/text
equals the heading content, while the body remains in a separate node — locate
the assertion around the second it('should render heading in a View block when
separateHeading is set') and replace or extend the contains checks with a
structural assertion that the heading node is wrapped by a View node.

In `@app/components/remove_markdown/index.tsx`:
- Around line 146-156: The renderParagraph callback's boolean parameter first is
unclear; add a short inline comment above the renderParagraph definition
explaining that first === true indicates the paragraph is the first paragraph
after a heading (used to decide rendering when separateHeading and a two-line
preview via numberOfLines/paragraphLines are in effect). Mention
renderParagraph, first, separateHeading, paragraphLines, numberOfLines and
headingLineCount so maintainers understand the interaction and why only the
first paragraph may be rendered.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b367b8c5-d504-46a6-a701-cebed4b1aa02

📥 Commits

Reviewing files that changed from the base of the PR and between 7ed2f4d and 94d2a7a.

📒 Files selected for processing (5)
  • app/components/remove_markdown/index.test.tsx
  • app/components/remove_markdown/index.tsx
  • app/screens/global_threads/threads_list/thread/thread.tsx
  • app/utils/markdown/index.ts
  • types/global/markdown.ts

@avasconcelos114
Copy link
Copy Markdown
Contributor Author

Let me know whether I should be running each of the E2E Detox tests for this :)

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 25, 2026

Coverage Comparison Report

Generated on March 27, 2026 at 13:54:31 UTC

+-----------------+------------+------------+-----------+
| Metric          | Main       | This PR    | Diff      |
+-----------------+------------+------------+-----------+
| Lines           |     85.15% |     85.15% |     0.00% |
| Statements      |     85.02% |     85.02% |     0.00% |
| Branches        |     72.06% |     72.06% |     0.00% |
| Functions       |     83.99% |     83.99% |     0.00% |
+-----------------+------------+------------+-----------+
| Total           |     81.55% |     81.55% |     0.00% |
+-----------------+------------+------------+-----------+

Copy link
Copy Markdown
Contributor

@matthewbirtch matthewbirtch left a comment

Choose a reason for hiding this comment

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

thanks @avasconcelos114! LGTM

I think the spacing request between the heading and the body was intended to be an inline space, not a paragraph space. Having said that, I don't mind the heading being on its own line, I just don't think we need the vertical spacing between heading and body. So we can remove the marginBottom on the headingBlock in the thread list context I think.

Copy link
Copy Markdown
Contributor

@larkox larkox left a comment

Choose a reason for hiding this comment

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

One nitpick, and one question to understand better the PR.

);
};

const RemoveMarkdown = ({enableEmoji, enableChannelLink, enableHardBreak, enableSoftBreak, enableCodeSpan, baseStyle, numberOfLines, separateHeading, value}: Props) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For better visibility on what is added or removed in the future, can you put every property in a different line?

);
};

const RemoveMarkdown = ({enableEmoji, enableChannelLink, enableHardBreak, enableSoftBreak, enableCodeSpan, baseStyle, numberOfLines, separateHeading, value}: Props) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What exactly is supposed to achieve the separateHeading prop?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My first iteration of this had the heading being rendered in a separate line from the rest if the numberOfLines prop had been passed to the component

it felt strange to have the numberOfLines dictate how the heading was rendered so I added a separateHeading prop that when present, will make sure that there is always a line break between the heading and body of the message

and when missing this prop, it should default to the same behavior as it had prior to this PR, as the RemoveMarkdown component is used by the AnnouncementBanner and ChannelBanner components as well

@avasconcelos114
Copy link
Copy Markdown
Contributor Author

The marginBottom has been removed (for now I did preserve the logic to keep the heading in its own line, but I can remove it if deemed better)

In this screenshot, the post that contains a heading is the third one with the rabbit emoji
image

Copy link
Copy Markdown
Contributor

@matthewbirtch matthewbirtch left a comment

Choose a reason for hiding this comment

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

Thanks @avasconcelos114. Looks good from a UI perspective.

@avasconcelos114
Copy link
Copy Markdown
Contributor Author

@larkox gentle reminder to look through this whenever you can :)

@matthewbirtch matthewbirtch removed the 2: UX Review Requires review by a UX Designer label Apr 7, 2026
@avasconcelos114 avasconcelos114 added the E2E/Run Triggers E2E tests on both iOS and Android via Matterwick label Apr 8, 2026
@github-actions github-actions bot removed the E2E/Run Triggers E2E tests on both iOS and Android via Matterwick label Apr 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2: Dev Review Requires review by a core commiter release-note

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants