Skip to content

[Due for payment 2025-04-17] [Due for payment 2025-04-10] [$250] Markdown - Nested markdown not displayed in conversation #58468

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
8 of 16 tasks
IuliiaHerets opened this issue Mar 14, 2025 · 33 comments
Assignees
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor

Comments

@IuliiaHerets
Copy link

IuliiaHerets commented Mar 14, 2025

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Version Number: v9.1.13-0
Reproducible in staging?: Yes
Reproducible in production?: Yes
If this was caught during regression testing, add the test name, ID and link from TestRail: https://expensify.testrail.io/index.php?/tests/view/5740356
Issue reported by: Applause Internal Team
Device used: Windows 11/ Chrome, Android 13/ chrome
App Component: Other

Action Performed:

  1. sign in to staging.new.expensify.com
  2. Navigate to a conversation
  3. Send a comment with a nested markdown (eg. bold or bold)

Expected Result:

All markdown applied are shown in conversation.

Actual Result:

Only a single markdown of nested markdown is displayed in a conversation.

Workaround:

Unknown

Platforms:

  • Android: Standalone
  • Android: HybridApp
  • Android: mWeb Chrome
  • iOS: Standalone
  • iOS: HybridApp
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

If you haven’t already, check out our contributing guidelines for onboarding and email [email protected] to request to join our Slack channel!


Version Number: v9.1.13-0
Reproducible in staging?: Yes
Reproducible in production?: No
If this was caught on HybridApp, is this reproducible on New Expensify Standalone?: N/A
If this was caught during regression testing, add the test name, ID and link from TestRail: N/A
Email or phone of affected tester (no customers): N/A
Issue reported by: Applause Internal Team
Device used: Windows 11/ Chrome, Android 13/ chrome
App Component: Other

Action Performed:

  1. sign in to staging.new.expensify.com
  2. Navigate to a conversation
  3. Send a comment with a nested markdown (eg. _*bold*_ or *_bold_*)

Expected Result:

All markdown applied are shown in conversation.

Actual Result:

Only a single markdown of nested markdown is displayed in a conversation.

Workaround:

Unknown

Platforms:

  • Android: Standalone
  • Android: HybridApp
  • Android: mWeb Chrome
  • iOS: Standalone
  • iOS: HybridApp
  • iOS: mWeb Safari
  • MacOS: Chrome / Safari
  • MacOS: Desktop

Screenshots/Videos

Bug6770480_1741944295410.bandicam_2025-03-14_12-10-17-815.1.mp4
Upwork Automation - Do Not Edit
  • Upwork Job URL: https://www.upwork.com/jobs/~021901686536886743365
  • Upwork Job ID: 1901686536886743365
  • Last Price Increase: 2025-03-17
Issue OwnerCurrent Issue Owner: @OfstadC
@IuliiaHerets IuliiaHerets added Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 labels Mar 14, 2025
Copy link

melvin-bot bot commented Mar 14, 2025

Triggered auto assignment to @OfstadC (Bug), see https://stackoverflow.com/c/expensify/questions/14418 for more details. Please add this bug to a GH project, as outlined in the SO.

@CyberAndrii
Copy link
Contributor

CyberAndrii commented Mar 14, 2025

Proposal

Please re-state the problem that we are trying to solve in this issue.

Nested markdown is not displayed in conversation.

What is the root cause of that problem?

In both EMRenderer.ts and StrongRenderer.ts we use styles.webViewStyles.baseFontStyle which sets fontWeight: 400 and fontStyle: normal.

To make text italic we apply fontStyle: italic;
to make text bold we apply fontWeight: 700.

When we have nested tags like this

<strong>
    <em>text</em>
</strong>

the following properties are applied

  • strong => fontStyle: normal; fontWeight: 700.
  • em => fontStyle: italic; fontWeight: 400.

You can see that the em tag has fontWeight set to 400 when it should be 700. This is caused by styles.webViewStyles.baseFontStyle setting properties that should instead be inherited.

What changes do you think we should make in order to solve the problem?

One solution would be to apply fontStyle: 'inherit' in EMRenderer.ts and fontWeight: 'inherit' in StrongRenderer.ts. This approach would work, but the compiler will show an error because React Native does not allow style values to be set to inherit.

Instead we can manually apply the correct font family depending on whether strong is a child of em or vice versa. First, add these new functions to htmlEngineUtils.ts

function isChildOfStrong(tnode: TNode): boolean {
    return isChildOfNode(tnode, (node) => node.domNode?.name !== undefined && node.domNode.name.toLowerCase() === 'strong');
}
function isChildOfEm(tnode: TNode): boolean {
    return isChildOfNode(tnode, (node) => node.domNode?.name !== undefined && node.domNode.name.toLowerCase() === 'em');
}

Then modify StrongRenderer.ts so that it uses bold+italic font when the strong tag is a child of em, and bold font otherwise

Code
 function StrongRenderer({tnode}: CustomRendererProps<TText | TPhrasing>) {
     const styles = useThemeStyles();
     const isChildOfTaskTitle = HTMLEngineUtils.isChildOfTaskTitle(tnode);
+    const isChildOfEm = HTMLEngineUtils.isChildOfEm(tnode);
+
+    const fontFamily = isChildOfEm
+        ? FontUtils.fontFamily.platform.EXP_NEUE_BOLD_ITALIC
+        : FontUtils.fontFamily.platform.EXP_NEUE_BOLD;
 
     return 'data' in tnode ? (
-        <Text style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}>{tnode.data}</Text>
+        <Text style={[styles.webViewStyles.baseFontStyle, fontFamily, isChildOfTaskTitle && styles.taskTitleMenuItem]}>{tnode.data} </Text>
     ) : (
         <TNodeChildrenRenderer
             tnode={tnode}
             renderChild={(props) => {
                 return (
                     <Text
-                        style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}
+                        style={[styles.webViewStyles.baseFontStyle, fontFamily, isChildOfTaskTitle && styles.taskTitleMenuItem]}
                         key={props.key}
                     >

Similarly update EMRenderer.ts. However, instead of using HTMLEngineUtils.isChildOfEm use HTMLEngineUtils.isChildOfStrong

Code
 function EMRenderer({tnode}: CustomRendererProps<TText | TPhrasing>) {
     const styles = useThemeStyles();
     const isChildOfTaskTitle = HTMLEngineUtils.isChildOfTaskTitle(tnode);
+    const isChildOfStrong = HTMLEngineUtils.isChildOfStrong(tnode);
+
+    const fontFamily = isChildOfStrong 
+        ? FontUtils.fontFamily.platform.EXP_NEUE_BOLD_ITALIC
+        : FontUtils.fontFamily.platform.EXP_NEUE_ITALIC;
     
     return 'data' in tnode ? (
-        <Text style={[styles.webViewStyles.baseFontStyle, styles.webViewStyles.tagStyles.em, isChildOfTaskTitle && styles.taskTitleMenuItemItalic]}>{tnode.data}</Text>
+        <Text style={[styles.webViewStyles.baseFontStyle, fontFamily, isChildOfTaskTitle && styles.taskTitleMenuItemItalic]}>{tnode.data}</Text>
     ) : (
         <TNodeChildrenRenderer
             tnode={tnode}
             renderChild={(props) => {
                 return (
                     <Text
-                        style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}
+                        style={[styles.webViewStyles.baseFontStyle, fontFamily, isChildOfTaskTitle && styles.taskTitleMenuItemItalic]}
                         key={props.key}
                     >

Result:

Image

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

Render markdown such as _*text*_ and *_text_* and validate that the correct styles are applied to these tags.

@bernhardoj
Copy link
Contributor

Proposal

Please re-state the problem that we are trying to solve in this issue.

Nested markdown doesn't have correct style.

What is the root cause of that problem?

We now have a custom rendered for bold, italic, etc. If we look at the bold renderer, for example, we kinda "hardcoded" the style to only be a bold text, without considering a nested markdown style.

function StrongRenderer({tnode}: CustomRendererProps<TText | TPhrasing>) {
const styles = useThemeStyles();
const isChildOfTaskTitle = HTMLEngineUtils.isChildOfTaskTitle(tnode);
return 'data' in tnode ? (
<Text style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}>{tnode.data}</Text>
) : (
<TNodeChildrenRenderer

What changes do you think we should make in order to solve the problem?

We need to replace styles.webViewStyles.baseFontStyle with the style props.

<Text style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}>{tnode.data}</Text>
) : (
<TNodeChildrenRenderer
tnode={tnode}
renderChild={(props) => {
return (
<Text
style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}

<Text style={[style, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}>{tnode.data}</Text>

style props contain all the computed styles from the parents.

We need to apply this to bold, italic, etc renderer where nested markdown is allowed.

What specific scenarios should we cover in automated tests to prevent reintroducing this issue in the future?

N/A

@melvin-bot melvin-bot bot added the Overdue label Mar 17, 2025
@OfstadC OfstadC added the External Added to denote the issue can be worked on by a contributor label Mar 17, 2025
@melvin-bot melvin-bot bot changed the title Markdown - Nested markdown not displayed in conversation [$250] Markdown - Nested markdown not displayed in conversation Mar 17, 2025
Copy link

melvin-bot bot commented Mar 17, 2025

Job added to Upwork: https://www.upwork.com/jobs/~021901686536886743365

@melvin-bot melvin-bot bot added the Help Wanted Apply this label when an issue is open to proposals by contributors label Mar 17, 2025
Copy link

melvin-bot bot commented Mar 17, 2025

Triggered auto assignment to Contributor-plus team member for initial proposal review - @rojiphil (External)

@melvin-bot melvin-bot bot removed the Overdue label Mar 17, 2025
Copy link

melvin-bot bot commented Mar 21, 2025

@rojiphil Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

@melvin-bot melvin-bot bot added the Overdue label Mar 21, 2025
@rojiphil
Copy link
Contributor

Thanks for the proposals.
@bernhardoj proposal to apply style props for all the renderers where nested markdown is allowed LGTM.
🎀👀🎀 C+ reviewed

Copy link

melvin-bot bot commented Mar 21, 2025

Triggered auto assignment to @srikarparsi, see https://stackoverflow.com/c/expensify/questions/7972 for more details.

@melvin-bot melvin-bot bot removed the Help Wanted Apply this label when an issue is open to proposals by contributors label Mar 21, 2025
@bernhardoj
Copy link
Contributor

Hey, so while working on the PR, I noticed that when applying the style props to the Text inside TNodeChildrenRenderer doesn't work. Looks like the style from props.childElement still overrides it.

return 'data' in tnode ? (
<Text style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}>{tnode.data}</Text>
) : (
<TNodeChildrenRenderer
tnode={tnode}
renderChild={(props) => {
return (
<Text
style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}
key={props.key}
>
{props.childElement}
</Text>
);
}}

I think this whole custom renderer for the task title is a bit of a mess. If we see the StrongRenderer above and compare it to the EMRendere below,

return 'data' in tnode ? (
<Text style={[styles.webViewStyles.baseFontStyle, styles.webViewStyles.tagStyles.em, isChildOfTaskTitle && styles.taskTitleMenuItemItalic]}>{tnode.data}</Text>
) : (
<TNodeChildrenRenderer
tnode={tnode}
renderChild={(props) => {
return (
<Text
style={[styles.webViewStyles.baseFontStyle, styles.strong, isChildOfTaskTitle && styles.taskTitleMenuItem]}
key={props.key}
>
{props.childElement}
</Text>
);
}}

we can notice that the style of the Text inside TNodeChildrenRenderer has a strong style, even though it's for the italic renderer, so I assume they just copied the implementation from EMRenderer to StrongRenderer.

So, I'm thinking of a better and cleaner solution for the task title HTML renderer and will also solve this issue. For context, the reason we add a custom renderer for italic, strong, etc. is that we want to apply taskTitleMenuItemItalic or taskTitleMenuItem style when the text is inside a task title view. <task-title><em>test</em></task-title>.

By default, EM has a EXP_NEUE_ITALIC font family, and inside a task title, we want it to be EXP_NEW_KANSAS_MEDIUM_ITALIC, so a custom renderer is created to override the style.

App/src/styles/index.ts

Lines 152 to 156 in 8deddfa

tagStyles: {
em: {
// We set fontFamily and fontStyle directly in order to avoid overriding fontWeight.
fontFamily: FontUtils.fontFamily.platform.EXP_NEUE_ITALIC.fontFamily,
fontStyle: FontUtils.fontFamily.platform.EXP_NEUE_ITALIC.fontStyle,

My new proposal is:
First, remove the new added custom renderer (strong, em, etc.). Next, we will remove the font family style from em here (we will need adjustment to the default style as needed for other tags too, such as adding back the default style for strong that was removed).

App/src/styles/index.ts

Lines 153 to 157 in 8deddfa

em: {
// We set fontFamily and fontStyle directly in order to avoid overriding fontWeight.
fontFamily: FontUtils.fontFamily.platform.EXP_NEUE_ITALIC.fontFamily,
fontStyle: FontUtils.fontFamily.platform.EXP_NEUE_ITALIC.fontStyle,
},

So, how will we handle the styling? We will use mixedUAStyles (or specifically, getMixedUAStyles), like we have for strong here.

strong: HTMLElementModel.fromCustomModel({
tagName: 'strong',
mixedUAStyles: {whiteSpace: 'pre'},
contentModel: HTMLContentModel.textual,
}),

For example, for italic/em, we will do it like this:

em: HTMLElementModel.fromCustomModel({
    tagName: 'em',
    getMixedUAStyles: (tnode) => {
        const isChildOfTaskTitle = HTMLEngineUtils.isChildOfTaskTitle(tnode as TNode);
        return {fontFamily: FontUtils.fontFamily.platform.EXP_NEUE_ITALIC.fontFamily, ...(isChildOfTaskTitle ? styles.taskTitleMenuItemItalic : {})};
    },
    contentModel: HTMLContentModel.textual,
}),

Before:
Image

After: (the same as on main)
Image

No need for custom renderer.

@rojiphil @srikarparsi Let me know what you think!

@bernhardoj
Copy link
Contributor

The above new solution will also fix #58883

Copy link

melvin-bot bot commented Mar 25, 2025

@rojiphil Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

@melvin-bot melvin-bot bot added the Overdue label Mar 25, 2025
@srikarparsi
Copy link
Contributor

Hey @rojiphil, have you had a chance to look at this comment

@rojiphil
Copy link
Contributor

@bernhardoj Yeah. Removing the custom renderer and adding styling using getMixedUAStyles LGTM. Please raise a PR for this. Thanks

@melvin-bot melvin-bot bot removed the Overdue label Mar 26, 2025
@melvin-bot melvin-bot bot added Weekly KSv2 and removed Weekly KSv2 labels Apr 3, 2025
@bernhardoj
Copy link
Contributor

Opened a new PR

cc: @rojiphil

The issue is caused because I set the h1 element to textual instead of block.

@melvin-bot melvin-bot bot added Weekly KSv2 and removed Weekly KSv2 labels Apr 10, 2025
@melvin-bot melvin-bot bot changed the title [Due for payment 2025-04-10] [$250] Markdown - Nested markdown not displayed in conversation [Due for payment 2025-04-17] [Due for payment 2025-04-10] [$250] Markdown - Nested markdown not displayed in conversation Apr 10, 2025
@melvin-bot melvin-bot bot removed the Reviewing Has a PR in review label Apr 10, 2025
Copy link

melvin-bot bot commented Apr 10, 2025

Reviewing label has been removed, please complete the "BugZero Checklist".

Copy link

melvin-bot bot commented Apr 10, 2025

The solution for this issue has been 🚀 deployed to production 🚀 in version 9.1.25-4 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:

If no regressions arise, payment will be issued on 2025-04-17. 🎊

For reference, here are some details about the assignees on this issue:

  • @rojiphil requires payment through NewDot Manual Requests
  • @bernhardoj requires payment through NewDot Manual Requests

Copy link

melvin-bot bot commented Apr 10, 2025

@rojiphil @OfstadC @rojiphil The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the BugZero Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]

@melvin-bot melvin-bot bot added Daily KSv2 Overdue and removed Weekly KSv2 labels Apr 10, 2025
@OfstadC
Copy link
Contributor

OfstadC commented Apr 14, 2025

@rojiphil please complete BZ checklist prior to 2025-04-17 so we can issue payment 😃 Thanks!

@melvin-bot melvin-bot bot removed the Overdue label Apr 14, 2025
Copy link

melvin-bot bot commented Apr 17, 2025

Payment Summary

Upwork Job

BugZero Checklist (@OfstadC)

  • I have verified the correct assignees and roles are listed above and updated the necessary manual offers
  • I have verified that there are no duplicate or incorrect contracts on Upwork for this job (https://www.upwork.com/ab/applicants/1901686536886743365/hired)
  • I have paid out the Upwork contracts or cancelled the ones that are incorrect
  • I have verified the payment summary above is correct

@melvin-bot melvin-bot bot added the Overdue label Apr 17, 2025
@OfstadC
Copy link
Contributor

OfstadC commented Apr 17, 2025

@rojiphil Please complete BZ Checklist so payment can be issued here 😄 - Thank you!

@melvin-bot melvin-bot bot removed the Overdue label Apr 17, 2025
@OfstadC
Copy link
Contributor

OfstadC commented Apr 18, 2025

Bump @rojiphil

@melvin-bot melvin-bot bot added the Overdue label Apr 21, 2025
Copy link

melvin-bot bot commented Apr 22, 2025

@OfstadC Uh oh! This issue is overdue by 2 days. Don't forget to update your issues!

@rojiphil
Copy link
Contributor

Sorry for the delay here. Will complete the checklist in an hour or so.

@rojiphil rojiphil mentioned this issue Apr 22, 2025
49 tasks
@rojiphil
Copy link
Contributor

BugZero Checklist:

  • [Contributor] Classify the bug:
Bug classification

Source of bug:

  • 1a. Result of the original design (eg. a case wasn't considered)
  • 1b. Mistake during implementation
  • 1c. Backend bug
  • 1z. Other:

Where bug was reported:

  • 2a. Reported on production
  • 2b. Reported on staging (deploy blocker)
  • 2c. Reported on a PR
  • 2z. Other:

Who reported the bug:

  • 3a. Expensify user
  • [] 3b. Expensify employee
  • 3c. Contributor
  • 3d. QA
  • 3z. Other:
  • [Contributor] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake.

    Link to comment:

  • [Contributor] If the regression was CRITICAL (e.g. interrupts a core flow) A discussion in #expensify-open-source has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner.

    Link to discussion: Not Required. The existing checklist is good enough to capture such issues.

  • [Contributor] If it was decided to create a regression test for the bug, please propose the regression test steps using the template below to ensure the same bug will not reach production again.

Regression Test Proposal

Precondition:

Test:

  1. Send a nested markdown message text as follows:
_*bold*_ or *_bold_*
# *_test_*
  1. Verify that the markdown styles are applied

Do we agree 👍 or 👎

@OfstadC
Copy link
Contributor

OfstadC commented Apr 22, 2025

Payment Summary is accurate 😃

@melvin-bot melvin-bot bot removed the Overdue label Apr 22, 2025
@OfstadC OfstadC closed this as completed Apr 22, 2025
@bernhardoj
Copy link
Contributor

Requested in ND.

@garrettmknight
Copy link
Contributor

$250 approved for @rojiphil

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting Payment Auto-added when associated PR is deployed to production Bug Something is broken. Auto assigns a BugZero manager. Daily KSv2 External Added to denote the issue can be worked on by a contributor
Projects
None yet
Development

No branches or pull requests

7 participants