import { default as React, ComponentType } from 'react'; import { BaseNode, HtmlPolicy, MarkdownIt, ParsedNode, ParseOptions } from 'stream-markdown-parser'; import { CustomComponentMap, HtmlComponentDefinitions, HtmlComponentMap, StreamingComponentDefinitions, StreamingComponentMap } from './customComponents'; import { SmoothMarkdownStreamOptions } from './hooks/useSmoothMarkdownStream'; import { CodeBlockMonacoOptions, CodeBlockMonacoTheme, CodeBlockNodeProps, CodeBlockPreviewPayload, D2BlockNodeProps, InfographicBlockNodeProps, MermaidBlockNodeProps, ShikiCodeBlockProps } from './types/component-props'; type NodeRendererCodeBlockThemes = CodeBlockNodeProps['themes'] | ShikiCodeBlockProps['themes']; export type NodeRendererCodeBlockProps = Partial> & Partial> & { themes?: NodeRendererCodeBlockThemes; } & Record; export interface NodeRendererProps> = StreamingComponentMap, THtmlComponents extends Record = HtmlComponentMap> { content?: string; nodes?: readonly BaseNode[] | null; /** * Whether the input stream is complete (end-of-stream). When true, the parser * can stop emitting streaming "loading" nodes for unfinished constructs. */ final?: boolean; parseOptions?: ParseOptions; customMarkdownIt?: (md: MarkdownIt) => MarkdownIt; streamingComponents?: TStreamingComponents & StreamingComponentDefinitions; htmlComponents?: THtmlComponents & HtmlComponentDefinitions; /** Log parse/render timing stats (dev only). */ debugPerformance?: boolean; /** * Custom HTML-like tags that should be emitted as custom nodes (e.g. ['thinking']). * Forwarded to `getMarkdown()` and merged into parseOptions. */ customHtmlTags?: readonly string[]; htmlPolicy?: HtmlPolicy; viewportPriority?: boolean; codeBlockStream?: boolean; codeBlockDarkTheme?: CodeBlockMonacoTheme; codeBlockLightTheme?: CodeBlockMonacoTheme; codeBlockMonacoOptions?: CodeBlockMonacoOptions; renderCodeBlocksAsPre?: boolean; codeBlockMinWidth?: string | number; codeBlockMaxWidth?: string | number; codeBlockProps?: NodeRendererCodeBlockProps; mermaidProps?: Partial>; d2Props?: Partial>; infographicProps?: Partial>; showTooltips?: boolean; /** * Theme names or theme objects preloaded for Monaco-backed code blocks. * When Shiki code blocks are used, only string theme names are forwarded to * MarkdownCodeBlockNode / stream-markdown; theme objects are ignored. */ themes?: CodeBlockMonacoTheme[]; /** * Shiki language preload list forwarded to MarkdownCodeBlockNode. * * The default React code block renderer is Monaco-backed. This prop is used * when a custom `code_block` or language renderer uses MarkdownCodeBlockNode. */ langs?: readonly string[]; isDark?: boolean; customId?: string; indexKey?: number | string; /** Show a blinking typewriter cursor while streamed content grows. Default: false */ typewriter?: boolean; /** Enable/disable non-code-node enter and streamed-text fade animations. Default: true */ fade?: boolean; /** * Enable built-in smooth pacing for streaming `content` updates. * - `true`: force-enable smooth streaming (content mode only) * - `false`: force-disable smooth streaming * - `'auto'` (default): enable only when typewriter/incremental mode is active * Applies when rendering from `content` (not `nodes`). */ smoothStreaming?: boolean | 'auto'; /** Options forwarded to the built-in smooth streaming controller. Read once when the renderer is created. */ smoothStreamingOptions?: SmoothMarkdownStreamOptions; batchRendering?: boolean; initialRenderBatchSize?: number; renderBatchSize?: number; renderBatchDelay?: number; renderBatchBudgetMs?: number; renderBatchIdleTimeoutMs?: number; deferNodesUntilVisible?: boolean; maxLiveNodes?: number; liveNodeBuffer?: number; onCopy?: (code: string) => void; onHandleArtifactClick?: (payload: CodeBlockPreviewPayload) => void; onClick?: (event: React.MouseEvent) => void; onMouseOver?: (event: React.MouseEvent) => void; onMouseOut?: (event: React.MouseEvent) => void; } export interface RenderContext { customId?: string; isDark?: boolean; final?: boolean; indexKey?: string; typewriter?: boolean; /** Enable/disable fade animations. Default: true */ fade?: boolean; textStreamState?: Map; streamRenderVersion?: number; customComponents?: CustomComponentMap; streamingComponents?: StreamingComponentMap; htmlComponents?: HtmlComponentMap; customHtmlTags?: readonly string[]; htmlPolicy?: HtmlPolicy; codeBlockProps?: NodeRendererCodeBlockProps; mermaidProps?: Partial>; d2Props?: Partial>; infographicProps?: Partial>; showTooltips?: boolean; codeBlockStream?: boolean; renderCodeBlocksAsPre?: boolean; codeBlockThemes?: { themes?: CodeBlockMonacoTheme[]; darkTheme?: CodeBlockMonacoTheme; lightTheme?: CodeBlockMonacoTheme; monacoOptions?: CodeBlockMonacoOptions; minWidth?: string | number; maxWidth?: string | number; langs?: readonly string[]; }; events: { onCopy?: (code: string) => void; onHandleArtifactClick?: (payload: CodeBlockPreviewPayload) => void; }; } export type RenderNodeFn = (node: ParsedNode, key: React.Key, ctx: RenderContext) => React.ReactNode; export {};