Fix iOS markdown image rendering
This commit is contained in:
@@ -34,6 +34,7 @@ import { isRenderedMarkdownFile } from "@/components/file-pane-render-mode";
|
|||||||
import { isWeb } from "@/constants/platform";
|
import { isWeb } from "@/constants/platform";
|
||||||
import { createMarkdownStyles } from "@/styles/markdown-styles";
|
import { createMarkdownStyles } from "@/styles/markdown-styles";
|
||||||
import { getMarkdownListMarker, getMarkdownListSpacing } from "@/utils/markdown-list";
|
import { getMarkdownListMarker, getMarkdownListSpacing } from "@/utils/markdown-list";
|
||||||
|
import { markdownNodeContainsType } from "@/utils/markdown-ast";
|
||||||
import type { AttachmentMetadata } from "@/attachments/types";
|
import type { AttachmentMetadata } from "@/attachments/types";
|
||||||
import { useAttachmentPreviewUrl } from "@/attachments/use-attachment-preview-url";
|
import { useAttachmentPreviewUrl } from "@/attachments/use-attachment-preview-url";
|
||||||
import { persistAttachmentFromBytes } from "@/attachments/service";
|
import { persistAttachmentFromBytes } from "@/attachments/service";
|
||||||
@@ -395,7 +396,11 @@ function createFilePreviewMarkdownRules(): RenderRules {
|
|||||||
_parent: ASTNode[],
|
_parent: ASTNode[],
|
||||||
styles: MarkdownStyles,
|
styles: MarkdownStyles,
|
||||||
) => (
|
) => (
|
||||||
<MarkdownParagraphView key={node.key} paragraphStyle={styles.paragraph}>
|
<MarkdownParagraphView
|
||||||
|
key={node.key}
|
||||||
|
paragraphStyle={styles.paragraph}
|
||||||
|
containsImage={markdownNodeContainsType(node, "image")}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</MarkdownParagraphView>
|
</MarkdownParagraphView>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ export function MarkdownTextSpan({
|
|||||||
|
|
||||||
interface MarkdownParagraphViewProps {
|
interface MarkdownParagraphViewProps {
|
||||||
paragraphStyle: ViewStyle;
|
paragraphStyle: ViewStyle;
|
||||||
|
containsImage?: boolean;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMemo, type ReactNode } from "react";
|
import { useMemo, type ReactNode } from "react";
|
||||||
import type { StyleProp, TextProps, TextStyle, ViewStyle } from "react-native";
|
import { View, type StyleProp, type TextProps, type TextStyle, type ViewStyle } from "react-native";
|
||||||
import { UITextView } from "react-native-uitextview";
|
import { UITextView } from "react-native-uitextview";
|
||||||
|
|
||||||
interface MarkdownTextSpanProps {
|
interface MarkdownTextSpanProps {
|
||||||
@@ -41,6 +41,7 @@ export function MarkdownTextSpan({
|
|||||||
|
|
||||||
interface MarkdownParagraphViewProps {
|
interface MarkdownParagraphViewProps {
|
||||||
paragraphStyle: ViewStyle;
|
paragraphStyle: ViewStyle;
|
||||||
|
containsImage?: boolean;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,13 +53,23 @@ const MARKDOWN_PARAGRAPH_RESET: ViewStyle = { marginBottom: 0 };
|
|||||||
// ViewStyle is structurally compatible with the layout props paragraphs use
|
// ViewStyle is structurally compatible with the layout props paragraphs use
|
||||||
// (margin, padding, alignment); the cast lets the existing paragraphStyle
|
// (margin, padding, alignment); the cast lets the existing paragraphStyle
|
||||||
// flow through unchanged.
|
// flow through unchanged.
|
||||||
export function MarkdownParagraphView({ paragraphStyle, children }: MarkdownParagraphViewProps) {
|
export function MarkdownParagraphView({
|
||||||
const style = useMemo(
|
paragraphStyle,
|
||||||
|
containsImage = false,
|
||||||
|
children,
|
||||||
|
}: MarkdownParagraphViewProps) {
|
||||||
|
const textStyle = useMemo(
|
||||||
() => [paragraphStyle, MARKDOWN_PARAGRAPH_RESET] as StyleProp<TextStyle>,
|
() => [paragraphStyle, MARKDOWN_PARAGRAPH_RESET] as StyleProp<TextStyle>,
|
||||||
[paragraphStyle],
|
[paragraphStyle],
|
||||||
);
|
);
|
||||||
|
const viewStyle = useMemo(() => [paragraphStyle, MARKDOWN_PARAGRAPH_RESET], [paragraphStyle]);
|
||||||
|
|
||||||
|
if (containsImage) {
|
||||||
|
return <View style={viewStyle}>{children}</View>;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UITextView uiTextView selectable style={style}>
|
<UITextView uiTextView selectable style={textStyle}>
|
||||||
{children}
|
{children}
|
||||||
</UITextView>
|
</UITextView>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export function MarkdownTextSpan({
|
|||||||
|
|
||||||
interface MarkdownParagraphViewProps {
|
interface MarkdownParagraphViewProps {
|
||||||
paragraphStyle: ViewStyle;
|
paragraphStyle: ViewStyle;
|
||||||
|
containsImage?: boolean;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ import type { ToolCallDetail } from "@getpaseo/protocol/agent-types";
|
|||||||
import { buildToolCallPresentation } from "@/tool-calls/presentation";
|
import { buildToolCallPresentation } from "@/tool-calls/presentation";
|
||||||
import { resolveToolCallIcon } from "@/utils/tool-call-icon";
|
import { resolveToolCallIcon } from "@/utils/tool-call-icon";
|
||||||
import { getMarkdownListMarker, getMarkdownListSpacing } from "@/utils/markdown-list";
|
import { getMarkdownListMarker, getMarkdownListSpacing } from "@/utils/markdown-list";
|
||||||
|
import { markdownNodeContainsType } from "@/utils/markdown-ast";
|
||||||
import { useStableEvent } from "@/hooks/use-stable-event";
|
import { useStableEvent } from "@/hooks/use-stable-event";
|
||||||
import { HighlightedCodeBlock } from "@/components/highlighted-code-block";
|
import { HighlightedCodeBlock } from "@/components/highlighted-code-block";
|
||||||
import { splitMarkdownBlocks } from "@/utils/split-markdown-blocks";
|
import { splitMarkdownBlocks } from "@/utils/split-markdown-blocks";
|
||||||
@@ -1825,7 +1826,11 @@ export const AssistantMessage = memo(function AssistantMessage({
|
|||||||
_parent: ASTNode[],
|
_parent: ASTNode[],
|
||||||
styles: MarkdownStyles,
|
styles: MarkdownStyles,
|
||||||
) => (
|
) => (
|
||||||
<MarkdownParagraphView key={node.key} paragraphStyle={styles.paragraph}>
|
<MarkdownParagraphView
|
||||||
|
key={node.key}
|
||||||
|
paragraphStyle={styles.paragraph}
|
||||||
|
containsImage={markdownNodeContainsType(node, "image")}
|
||||||
|
>
|
||||||
{children}
|
{children}
|
||||||
</MarkdownParagraphView>
|
</MarkdownParagraphView>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { markdownNodeContainsType } from "./markdown-ast";
|
||||||
|
|
||||||
|
describe("markdownNodeContainsType", () => {
|
||||||
|
it("matches the node itself", () => {
|
||||||
|
expect(markdownNodeContainsType({ type: "image", children: [] }, "image")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("matches descendants", () => {
|
||||||
|
const paragraph = {
|
||||||
|
type: "paragraph",
|
||||||
|
children: [
|
||||||
|
{ type: "text", children: [] },
|
||||||
|
{
|
||||||
|
type: "link",
|
||||||
|
children: [{ type: "image", children: [] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(markdownNodeContainsType(paragraph, "image")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false when the type is absent", () => {
|
||||||
|
const paragraph = {
|
||||||
|
type: "paragraph",
|
||||||
|
children: [
|
||||||
|
{ type: "text", children: [] },
|
||||||
|
{ type: "strong", children: [{ type: "text", children: [] }] },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
expect(markdownNodeContainsType(paragraph, "image")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export interface MarkdownAstNodeWithChildren {
|
||||||
|
type: string;
|
||||||
|
children: MarkdownAstNodeWithChildren[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function markdownNodeContainsType(node: MarkdownAstNodeWithChildren, type: string): boolean {
|
||||||
|
if (node.type === type) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node.children.some((child) => markdownNodeContainsType(child, type));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user