fix(app): render bold/italic/strikethrough and line breaks via UITextView span on iOS (#1254)

* fix(app): render bold/italic/strikethrough via UITextView span on iOS

strong/em/s had no custom render rule and fell back to
react-native-markdown-display's defaults, which wrap children in a plain
RN <Text>. On iOS the paragraph/textgroup are native UITextViews
(markdown-text.ios.tsx); a plain <Text> nested inside is not hoisted into
a UITextViewChild, so its content rendered invisibly — bold/italic/
strikethrough silently disappeared (regression from #1153, v0.1.84).

Route strong/em/s through MarkdownInheritedText -> MarkdownTextSpan, the
same path text/textgroup already use, so the styled run composes as a
UITextViewChild on iOS and stays visible + selectable. Web/Android use a
plain <Text> for MarkdownTextSpan, so behavior there is unchanged.

Fixes #1253

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(app): render hard/soft line breaks via UITextView span on iOS

hardbreak/softbreak had no custom rule, so react-native-markdown-display
emitted a plain RN <Text>{"\n"}. Inside the paragraph UITextView that
plain <Text> is dropped (same root cause as strong/em/s/link): on iOS
hard line breaks vanished, and a softbreak between words joined them
("one\ntwo" -> "onetwo") — the "adjacent words dropped" symptom from the
original report.

Route both through MarkdownTextSpan so the newline composes as a
UITextViewChild on iOS; web/Android keep the same "\n".

Refs #1253

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Geoffrey <geoffrey.marc@consulting-for.edenred.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Geoffrey Marc
2026-06-01 09:57:06 +02:00
committed by GitHub
parent b8ccd543c4
commit 8c6abcb41f

View File

@@ -1622,6 +1622,67 @@ export const AssistantMessage = memo(function AssistantMessage({
{children}
</MarkdownInheritedText>
),
// strong/em/s have no custom rule in react-native-markdown-display's
// defaults beyond wrapping children in a plain RN <Text>. On iOS the
// paragraph/textgroup are native UITextViews (see markdown-text.ios.tsx),
// and a plain <Text> nested inside one is not hoisted into a
// UITextViewChild, so its content renders invisibly. Route these inline
// marks through MarkdownTextSpan (same path as text/textgroup) so the
// styled content composes and stays visible + selectable on iOS.
strong: (
node: ASTNode,
children: ReactNode[],
_parent: ASTNode[],
styles: MarkdownStyles,
inheritedStyles: TextStyle = {},
) => (
<MarkdownInheritedText
key={node.key}
inheritedStyles={inheritedStyles}
textStyle={styles.strong}
>
{children}
</MarkdownInheritedText>
),
em: (
node: ASTNode,
children: ReactNode[],
_parent: ASTNode[],
styles: MarkdownStyles,
inheritedStyles: TextStyle = {},
) => (
<MarkdownInheritedText
key={node.key}
inheritedStyles={inheritedStyles}
textStyle={styles.em}
>
{children}
</MarkdownInheritedText>
),
s: (
node: ASTNode,
children: ReactNode[],
_parent: ASTNode[],
styles: MarkdownStyles,
inheritedStyles: TextStyle = {},
) => (
<MarkdownInheritedText
key={node.key}
inheritedStyles={inheritedStyles}
textStyle={styles.s}
>
{children}
</MarkdownInheritedText>
),
// hardbreak/softbreak fall back to react-native-markdown-display's
// default, a plain RN <Text>{"\n"}. Inside the paragraph UITextView that
// plain <Text> is not hoisted into a UITextViewChild and is dropped (same
// root cause as strong/em/s) — so on iOS a hard line break vanished, and
// a softbreak between words jammed them together ("one\ntwo" -> "onetwo").
// Emit the break through MarkdownTextSpan so it composes on iOS; web and
// Android keep the same "\n" they rendered before.
hardbreak: (node: ASTNode) => <MarkdownTextSpan key={node.key}>{"\n"}</MarkdownTextSpan>,
softbreak: (node: ASTNode) => <MarkdownTextSpan key={node.key}>{"\n"}</MarkdownTextSpan>,
code_block: (
node: ASTNode,
_children: ReactNode[],