fix(app): render inline links via UITextView span on iOS (#1257)
AssistantMarkdownLink's native branch wrapped its children in a plain RN <Text>. On iOS that <Text> sits inside the paragraph's native UITextView and is not hoisted into a UITextViewChild, so link text (markdown links, bare URLs, and inline-code path links) was silently dropped — the same root cause as the bold/italic/strikethrough fix in this PR. Route the native link through MarkdownTextSpan so it composes as a UITextViewChild and stays visible + selectable. MarkdownTextSpan now forwards onPress/accessibilityRole across platforms: tappable on Android/web; on iOS react-native-uitextview nulls onPress on the root native view, so reliable tap-to-open is still tracked by #21 — but visible, selectable, copyable link text strictly beats an invisible one. Refs #1253 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:
co-authored by
Geoffrey
Claude Opus 4.8
parent
632c48fde3
commit
a3b0af9ac0
@@ -1,20 +1,39 @@
|
||||
import { useMemo, type ReactNode } from "react";
|
||||
import type { StyleProp, TextStyle, ViewStyle } from "react-native";
|
||||
import type { StyleProp, TextProps, TextStyle, ViewStyle } from "react-native";
|
||||
import { UITextView } from "react-native-uitextview";
|
||||
|
||||
interface MarkdownTextSpanProps {
|
||||
style?: StyleProp<TextStyle>;
|
||||
monoSurface?: boolean;
|
||||
children: ReactNode;
|
||||
// Links route through this span too (see assistant-file-links/link.tsx). A
|
||||
// plain <Text> nested in the paragraph UITextView is dropped, so the link
|
||||
// must be a UITextView span to be visible. onPress is forwarded best-effort:
|
||||
// react-native-uitextview nulls onPress on the root native view, so reliable
|
||||
// tap-to-open is still tracked by #21 — but visible+selectable text beats an
|
||||
// invisible link.
|
||||
onPress?: TextProps["onPress"];
|
||||
accessibilityRole?: TextProps["accessibilityRole"];
|
||||
}
|
||||
|
||||
// Inline span backed by UITextView so iOS gets native word-selection handles.
|
||||
// Used inside MarkdownParagraphView (which is also a UITextView on iOS); the
|
||||
// library's TextAncestorContext hoists these into UITextViewChild nodes so
|
||||
// selection drags can cross sibling spans (e.g. plain text → **bold** → code).
|
||||
export function MarkdownTextSpan({ style, children }: MarkdownTextSpanProps) {
|
||||
export function MarkdownTextSpan({
|
||||
style,
|
||||
children,
|
||||
onPress,
|
||||
accessibilityRole,
|
||||
}: MarkdownTextSpanProps) {
|
||||
return (
|
||||
<UITextView uiTextView selectable style={style}>
|
||||
<UITextView
|
||||
uiTextView
|
||||
selectable
|
||||
style={style}
|
||||
onPress={onPress}
|
||||
accessibilityRole={accessibilityRole}
|
||||
>
|
||||
{children}
|
||||
</UITextView>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user