/** * Response — a model's answer, rendered as it arrives. * * An answer is markdown. It has headings and lists and fenced code in it, * because that is what a model writes, and rendering it as one run of plain * text throws away the structure the model went to the trouble of producing. * * So this reads the markdown and renders it through the library's own parts — * `Typography` for prose, `CodeBlock` for fences, `Table` for tables. Nothing * here draws its own type or its own colours: an answer inside a message bubble * should look like the app it is in, not like a document viewer someone * embedded. * * ```tsx * {text} * ``` * * ## Why it is a whole component and not a `` * * Because the text is still arriving, and that changes everything about how it * has to be read. A token stream hands you every prefix of the final answer, so * a renderer sees `**bo`, then `**bol`, then `**bold**` — three documents, two * of which have literal asterisks in them. Render each faithfully and the * answer flickers between styles on nearly every frame, which is worse than no * formatting at all: the eye tracks the flicker instead of the words. * * `isStreaming` tells the reader to finish an unterminated construct at the end * of the input rather than escaping it — an open fence is a code block that is * still filling, an open `**` is bold text still being written. The rule it * works to is that no word already on screen may disappear when the next token * arrives; delimiters may vanish as they are recognised, words never do. * * ## Where the props come from * * With the AI SDK, `children` is the text of the assistant message's text parts * joined together, and `isStreaming` is `status === 'streaming'`. Join the * parts — one `Response` per part renders a heading in one component and the * paragraph under it in another, and neither knows about the other. */ import { type ComponentType } from 'react'; import { type ViewProps } from 'react-native'; export type { Block as ResponseBlock, InlineToken as ResponseInline } from './markdown.js'; export interface ResponseComponents { /** Replaces the whole code block — for a runnable snippet, or a diff viewer. */ code?: ComponentType<{ code: string; language?: string; streaming: boolean; }>; /** Replaces an image. Nothing is rendered for one by default. */ image?: ComponentType<{ src: string; alt: string; }>; } export interface ResponseProps extends Omit { className?: string; /** The markdown. */ children?: string; /** * Whether more is still coming. Finishes an unterminated construct at the end * of the text instead of escaping it, so the answer does not flicker between * styles as its delimiters arrive. */ isStreaming?: boolean; /** Turns off speculative completion entirely, even while streaming. */ parseIncompleteMarkdown?: boolean; /** What a link does. Opens it with the system handler by default. */ onLinkPress?: (href: string) => void; /** * Schemes a link is allowed to open. A model can write any URL it likes, and * an answer is not a trusted document — so the default list is the four that * cannot do anything but navigate. */ allowedLinkPrefixes?: string[]; /** Swap out how a block is drawn. */ components?: ResponseComponents; /** Line numbers in fenced code. */ showLineNumbers?: boolean; } declare function ResponseRoot({ className, children, isStreaming, parseIncompleteMarkdown, onLinkPress, allowedLinkPrefixes, components, showLineNumbers, ...props }: ResponseProps): import("react").JSX.Element; /** * Re-renders only when the text changes. * * A stream re-renders its parent on every token, and everything else the parent * hands down — the callbacks, the overrides — is usually a fresh object each * time. Comparing the one prop that actually decides the output keeps a long * answer from re-parsing because a sibling moved. */ export declare const Response: import("react").MemoExoticComponent; //# sourceMappingURL=index.d.ts.map