@lofcz/streamdown 2.9.1 → 2.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/chunk-NE4QKYRI.js +29 -0
  2. package/dist/highlighted-body-5PIGDDHF.js +2 -0
  3. package/dist/hooks/use-deferred-render.d.ts +57 -0
  4. package/dist/index.d.ts +53 -498
  5. package/dist/index.js +1 -1
  6. package/dist/lib/animate.d.ts +66 -0
  7. package/dist/lib/block-incomplete-context.d.ts +14 -0
  8. package/dist/lib/code-block/body.d.ts +12 -0
  9. package/dist/lib/code-block/container.d.ts +8 -0
  10. package/dist/lib/code-block/context.d.ts +6 -0
  11. package/dist/lib/code-block/copy-button.d.ts +9 -0
  12. package/dist/lib/code-block/download-button.d.ts +9 -0
  13. package/dist/lib/code-block/header.d.ts +5 -0
  14. package/dist/lib/code-block/highlighted-body.d.ts +12 -0
  15. package/dist/lib/code-block/index.d.ts +13 -0
  16. package/dist/lib/code-block/skeleton.d.ts +1 -0
  17. package/dist/lib/components.d.ts +2 -0
  18. package/dist/lib/detect-direction.d.ts +13 -0
  19. package/dist/lib/icon-context.d.ts +23 -0
  20. package/dist/lib/icons.d.ts +14 -0
  21. package/dist/lib/image.d.ts +5 -0
  22. package/dist/lib/incomplete-code-utils.d.ts +24 -0
  23. package/dist/lib/link-modal.d.ts +8 -0
  24. package/dist/lib/markdown.d.ts +30 -0
  25. package/dist/lib/mermaid/download-button.d.ts +11 -0
  26. package/dist/lib/mermaid/fullscreen-button.d.ts +10 -0
  27. package/dist/lib/mermaid/index.d.ts +10 -0
  28. package/dist/lib/mermaid/pan-zoom.d.ts +19 -0
  29. package/dist/lib/mermaid/utils.d.ts +41 -0
  30. package/dist/lib/parse-blocks.d.ts +12 -0
  31. package/dist/lib/plugin-context.d.ts +29 -0
  32. package/dist/lib/plugin-types.d.ts +156 -0
  33. package/dist/lib/prefix-context.d.ts +12 -0
  34. package/dist/lib/preprocess-custom-tags.d.ts +19 -0
  35. package/dist/lib/preprocess-literal-tag-content.d.ts +24 -0
  36. package/dist/lib/rehype/literal-tag-content.d.ts +12 -0
  37. package/dist/lib/rehype/markdown-in-custom-tags.d.ts +16 -0
  38. package/dist/lib/remark/code-meta.d.ts +9 -0
  39. package/dist/lib/remark/container-alerts.d.ts +60 -0
  40. package/dist/lib/remark/escape-html.d.ts +3 -0
  41. package/dist/lib/remark/github-alerts.d.ts +16 -0
  42. package/dist/lib/scroll-lock.d.ts +2 -0
  43. package/dist/lib/scrollable.d.ts +7 -0
  44. package/dist/lib/streamdown-context.d.ts +107 -0
  45. package/dist/lib/table/copy-dropdown.d.ts +8 -0
  46. package/dist/lib/table/download-dropdown.d.ts +16 -0
  47. package/dist/lib/table/fullscreen-button.d.ts +8 -0
  48. package/dist/lib/table/index.d.ts +10 -0
  49. package/dist/lib/table/utils.d.ts +9 -0
  50. package/dist/lib/tailwind-classes.d.ts +2 -4
  51. package/dist/lib/tailwind-classes.js +1 -1
  52. package/dist/lib/translations-context.d.ts +39 -0
  53. package/dist/lib/utils.d.ts +23 -0
  54. package/dist/mermaid-L7RAWDBU.js +2 -0
  55. package/package.json +8 -5
  56. package/styles.css +28 -0
  57. package/dist/chunk-WRHXGPDT.js +0 -27
  58. package/dist/highlighted-body-33HEA3YT.js +0 -2
  59. package/dist/mermaid-RQAJEEXV.js +0 -2
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Context that indicates whether the current block has an incomplete code fence.
3
+ * True when: streaming is active AND this is the last block AND it has an unclosed code fence.
4
+ */
5
+ declare const BlockIncompleteContext: import("react").Context<boolean>;
6
+ /**
7
+ * Hook to check if the current block has an incomplete (unclosed) code fence.
8
+ *
9
+ * Returns `true` when the code fence in this block is still being streamed.
10
+ * Useful for deferring expensive renders (syntax highlighting, Mermaid diagrams)
11
+ * until the code block is complete.
12
+ */
13
+ export declare const useIsCodeFenceIncomplete: () => boolean;
14
+ export { BlockIncompleteContext };
@@ -0,0 +1,12 @@
1
+ import { type ComponentProps } from "react";
2
+ import type { HighlightResult } from "../plugin-types";
3
+ type CodeBlockBodyProps = ComponentProps<"div"> & {
4
+ maxHeight?: number | string;
5
+ result: HighlightResult;
6
+ language: string;
7
+ startLine?: number;
8
+ /** Show line numbers in code blocks. @default true */
9
+ lineNumbers?: boolean;
10
+ };
11
+ export declare const CodeBlockBody: import("react").MemoExoticComponent<({ children, result, language, className, maxHeight, startLine, lineNumbers, ...rest }: CodeBlockBodyProps) => import("react/jsx-runtime").JSX.Element>;
12
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { ComponentProps } from "react";
2
+ type CodeBlockContainerProps = ComponentProps<"div"> & {
3
+ language: string;
4
+ /** Whether the code block is still being streamed (incomplete) */
5
+ isIncomplete?: boolean;
6
+ };
7
+ export declare const CodeBlockContainer: ({ className, language, style, isIncomplete, ...props }: CodeBlockContainerProps) => import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,6 @@
1
+ interface CodeBlockContextType {
2
+ code: string;
3
+ }
4
+ export declare const CodeBlockContext: import("react").Context<CodeBlockContextType>;
5
+ export declare const useCodeBlockContext: () => CodeBlockContextType;
6
+ export {};
@@ -0,0 +1,9 @@
1
+ import { type ComponentProps } from "react";
2
+ export type CodeBlockCopyButtonProps = ComponentProps<"button"> & {
3
+ onCopy?: () => void;
4
+ onError?: (error: Error) => void;
5
+ timeout?: number;
6
+ };
7
+ export declare const CodeBlockCopyButton: ({ onCopy, onError, timeout, children, className, code: propCode, ...props }: CodeBlockCopyButtonProps & {
8
+ code?: string;
9
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { type ComponentProps } from "react";
2
+ export type CodeBlockDownloadButtonProps = ComponentProps<"button"> & {
3
+ onDownload?: () => void;
4
+ onError?: (error: Error) => void;
5
+ };
6
+ export declare const CodeBlockDownloadButton: ({ onDownload, onError, language, children, className, code: propCode, ...props }: CodeBlockDownloadButtonProps & {
7
+ code?: string;
8
+ language?: string;
9
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,5 @@
1
+ interface CodeBlockHeaderProps {
2
+ language: string;
3
+ }
4
+ export declare const CodeBlockHeader: ({ language }: CodeBlockHeaderProps) => import("react/jsx-runtime").JSX.Element;
5
+ export {};
@@ -0,0 +1,12 @@
1
+ import { type HTMLAttributes } from "react";
2
+ import type { HighlightResult } from "../plugin-types";
3
+ type HighlightedCodeBlockBodyProps = HTMLAttributes<HTMLDivElement> & {
4
+ code: string;
5
+ language: string;
6
+ maxHeight?: number | string;
7
+ raw: HighlightResult;
8
+ startLine?: number;
9
+ lineNumbers?: boolean;
10
+ };
11
+ export declare const HighlightedCodeBlockBody: ({ code, language, maxHeight, raw, className, startLine, lineNumbers, ...rest }: HighlightedCodeBlockBodyProps) => import("react/jsx-runtime").JSX.Element;
12
+ export {};
@@ -0,0 +1,13 @@
1
+ import { type HTMLAttributes } from "react";
2
+ type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {
3
+ code: string;
4
+ language: string;
5
+ /** Whether the code block is still being streamed (incomplete) */
6
+ isIncomplete?: boolean;
7
+ /** Custom starting line number for line numbering (default: 1) */
8
+ startLine?: number;
9
+ /** Show line numbers in code blocks. @default true */
10
+ lineNumbers?: boolean;
11
+ };
12
+ export declare const CodeBlock: ({ code, language, className, children, isIncomplete, startLine, lineNumbers, ...rest }: CodeBlockProps) => import("react/jsx-runtime").JSX.Element;
13
+ export {};
@@ -0,0 +1 @@
1
+ export declare const CodeBlockSkeleton: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import type { Options } from "./markdown";
2
+ export declare const components: Options["components"];
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Detect text direction using the "first strong character" algorithm.
3
+ * Strips common markdown syntax then finds the first Unicode letter
4
+ * with strong directionality.
5
+ *
6
+ * Note: markdown stripping is best-effort — nested formatting,
7
+ * multi-line fenced code blocks, and raw HTML are not fully handled.
8
+ * This is acceptable since the algorithm only needs to reach the first
9
+ * strong character, which is almost always in plain prose.
10
+ *
11
+ * @returns "rtl" if first strong char is RTL, "ltr" otherwise
12
+ */
13
+ export declare function detectTextDirection(text: string): "ltr" | "rtl";
@@ -0,0 +1,23 @@
1
+ import { type SVGProps } from "react";
2
+ export type IconComponent = React.ComponentType<SVGProps<SVGSVGElement> & {
3
+ size?: number;
4
+ }>;
5
+ export interface IconMap {
6
+ CheckIcon: IconComponent;
7
+ CopyIcon: IconComponent;
8
+ DownloadIcon: IconComponent;
9
+ ExternalLinkIcon: IconComponent;
10
+ Loader2Icon: IconComponent;
11
+ Maximize2Icon: IconComponent;
12
+ RotateCcwIcon: IconComponent;
13
+ XIcon: IconComponent;
14
+ ZoomInIcon: IconComponent;
15
+ ZoomOutIcon: IconComponent;
16
+ }
17
+ export declare const defaultIcons: IconMap;
18
+ export declare const IconContext: import("react").Context<IconMap>;
19
+ export declare const IconProvider: ({ icons, children, }: {
20
+ icons?: Partial<IconMap>;
21
+ children: React.ReactNode;
22
+ }) => import("react/jsx-runtime").JSX.Element;
23
+ export declare const useIcons: () => IconMap;
@@ -0,0 +1,14 @@
1
+ /** biome-ignore-all lint/a11y/noSvgWithoutTitle: "Streamdown icons" */
2
+ import type { SVGProps } from "react";
3
+ type IconProps = SVGProps<SVGSVGElement>;
4
+ export declare const CheckIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
5
+ export declare const CopyIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
6
+ export declare const DownloadIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const Loader2Icon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
8
+ export declare const Maximize2Icon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
9
+ export declare const RotateCcwIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
10
+ export declare const XIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
11
+ export declare const ExternalLinkIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
12
+ export declare const ZoomInIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
13
+ export declare const ZoomOutIcon: (props: IconProps) => import("react/jsx-runtime").JSX.Element;
14
+ export {};
@@ -0,0 +1,5 @@
1
+ import type { DetailedHTMLProps, ImgHTMLAttributes } from "react";
2
+ import type { ExtraProps } from "./markdown";
3
+ type ImageComponentProps = DetailedHTMLProps<ImgHTMLAttributes<HTMLImageElement>, HTMLImageElement> & ExtraProps;
4
+ export declare const ImageComponent: ({ node: _node, className, src, alt, onLoad: onLoadProp, onError: onErrorProp, onClick: onClickProp, ...props }: ImageComponentProps) => import("react/jsx-runtime").JSX.Element | null;
5
+ export {};
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Checks if a markdown string contains an incomplete (unclosed) code fence
3
+ * by walking line-by-line per the CommonMark spec.
4
+ *
5
+ * Only counts fences that start at the beginning of a line (with up to 3
6
+ * spaces of indentation). This avoids false positives from inline backticks
7
+ * and correctly handles fences of any length (3+).
8
+ *
9
+ * A closing fence must use the same character as the opening fence and be
10
+ * at least as long.
11
+ *
12
+ * @param markdown - The markdown string to check
13
+ * @returns true if there's an unclosed code fence
14
+ */
15
+ export declare const hasIncompleteCodeFence: (markdown: string) => boolean;
16
+ /**
17
+ * Checks if a markdown block contains a GFM table by looking for a
18
+ * delimiter row (e.g., `| --- | --- |`). A delimiter row confirms that
19
+ * the preceding header row forms a table.
20
+ *
21
+ * @param markdown - The markdown string to check
22
+ * @returns true if the block contains a table
23
+ */
24
+ export declare const hasTable: (markdown: string) => boolean;
@@ -0,0 +1,8 @@
1
+ interface LinkSafetyModalProps {
2
+ isOpen: boolean;
3
+ onClose: () => void;
4
+ onConfirm: () => void;
5
+ url: string;
6
+ }
7
+ export declare const LinkSafetyModal: ({ url, isOpen, onClose, onConfirm, }: LinkSafetyModalProps) => import("react").ReactPortal | null;
8
+ export {};
@@ -0,0 +1,30 @@
1
+ import type { Element, Parents } from "hast";
2
+ import type { ComponentType, JSX, ReactElement } from "react";
3
+ import type { Options as RemarkRehypeOptions } from "remark-rehype";
4
+ import type { PluggableList } from "unified";
5
+ export interface ExtraProps {
6
+ node?: Element | undefined;
7
+ }
8
+ export type AllowElement = (element: Readonly<Element>, index: number, parent: Readonly<Parents> | undefined) => boolean | null | undefined;
9
+ export type UrlTransform = (url: string, key: string, node: Readonly<Element>) => string | null | undefined;
10
+ export type Components = {
11
+ [Key in keyof JSX.IntrinsicElements]?: ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> | keyof JSX.IntrinsicElements;
12
+ } & {
13
+ inlineCode?: ComponentType<JSX.IntrinsicElements["code"] & ExtraProps>;
14
+ [key: string]: ComponentType<Record<string, unknown> & ExtraProps> | keyof JSX.IntrinsicElements | undefined;
15
+ };
16
+ export interface Options {
17
+ allowElement?: AllowElement;
18
+ allowedElements?: readonly string[];
19
+ children?: string;
20
+ components?: Components;
21
+ disallowedElements?: readonly string[];
22
+ rehypePlugins?: PluggableList;
23
+ remarkPlugins?: PluggableList;
24
+ remarkRehypeOptions?: Readonly<RemarkRehypeOptions>;
25
+ skipHtml?: boolean;
26
+ unwrapDisallowed?: boolean;
27
+ urlTransform?: UrlTransform;
28
+ }
29
+ export declare const Markdown: (options: Readonly<Options>) => ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
30
+ export declare const defaultUrlTransform: UrlTransform;
@@ -0,0 +1,11 @@
1
+ import type { MermaidConfig } from "../plugin-types";
2
+ interface MermaidDownloadDropdownProps {
3
+ chart: string;
4
+ children?: React.ReactNode;
5
+ className?: string;
6
+ config?: MermaidConfig;
7
+ onDownload?: (format: "mmd" | "png" | "svg") => void;
8
+ onError?: (error: Error) => void;
9
+ }
10
+ export declare const MermaidDownloadDropdown: ({ chart, children, className, onDownload, config, onError, }: MermaidDownloadDropdownProps) => import("react/jsx-runtime").JSX.Element;
11
+ export {};
@@ -0,0 +1,10 @@
1
+ import { type ComponentProps } from "react";
2
+ import type { MermaidConfig } from "../plugin-types";
3
+ type MermaidFullscreenButtonProps = ComponentProps<"button"> & {
4
+ chart: string;
5
+ config?: MermaidConfig;
6
+ onFullscreen?: () => void;
7
+ onExit?: () => void;
8
+ };
9
+ export declare const MermaidFullscreenButton: ({ chart, config, onFullscreen, onExit, className, ...props }: MermaidFullscreenButtonProps) => import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { MermaidConfig } from "../plugin-types";
2
+ interface MermaidProps {
3
+ chart: string;
4
+ className?: string;
5
+ config?: MermaidConfig;
6
+ fullscreen?: boolean;
7
+ showControls?: boolean;
8
+ }
9
+ export declare const Mermaid: ({ chart, className, config, fullscreen, showControls, }: MermaidProps) => import("react/jsx-runtime").JSX.Element;
10
+ export {};
@@ -0,0 +1,19 @@
1
+ import type { ReactNode } from "react";
2
+ interface PanZoomProps {
3
+ children: ReactNode;
4
+ className?: string;
5
+ contentSize?: {
6
+ height: number;
7
+ width: number;
8
+ } | null;
9
+ fitKey?: string;
10
+ fullscreen?: boolean;
11
+ initialZoom?: number;
12
+ isAutoFit?: boolean;
13
+ maxZoom?: number;
14
+ minZoom?: number;
15
+ showControls?: boolean;
16
+ zoomStep?: number;
17
+ }
18
+ export declare const PanZoom: ({ children, className, contentSize, fitKey: _fitKey, minZoom, maxZoom, zoomStep, showControls, initialZoom, isAutoFit, fullscreen, }: PanZoomProps) => import("react/jsx-runtime").JSX.Element;
19
+ export {};
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Ensure the SVG root element declares the xlink namespace when the document
3
+ * contains xlink-prefixed attributes (e.g. `xlink:href` used by Mermaid in
4
+ * C4 and sequence diagrams). Without the declaration the SVG is not valid
5
+ * XML: browsers refuse to load it as an image, causing PNG export to fail
6
+ * silently.
7
+ *
8
+ * The fix mirrors the approach used for other Mermaid SVG normalisation
9
+ * issues: detect the problem via a lightweight string check and patch the
10
+ * root `<svg>` opening tag in-place before any further processing.
11
+ *
12
+ * Falls back to the original string when the namespace is already present or
13
+ * when xlink-prefixed attributes are absent.
14
+ */
15
+ export declare const addXlinkNamespaceIfMissing: (svgString: string) => string;
16
+ /**
17
+ * Mermaid render output may be HTML-serialized. Serialize the SVG node as XML
18
+ * before downloading so embedded HTML like <br> becomes valid SVG markup.
19
+ */
20
+ export declare const serializeSvgForDownload: (svgString: string) => string;
21
+ /**
22
+ * Normalize Mermaid SVG dimensions for inline rendering.
23
+ * Mermaid emits width="100%" with max-width style, which can shrink very wide
24
+ * diagrams until text becomes unreadable.
25
+ */
26
+ export declare const getMermaidSvgSize: (svgString: string) => {
27
+ height: number;
28
+ width: number;
29
+ } | null;
30
+ /**
31
+ * Normalize Mermaid SVG dimensions for inline rendering.
32
+ * Mermaid emits width="100%" with max-width style, which can shrink very wide
33
+ * diagrams until text becomes unreadable.
34
+ */
35
+ export declare const normalizeMermaidInlineSvg: (svgString: string) => string;
36
+ /**
37
+ * Convert SVG string to PNG blob for export
38
+ */
39
+ export declare const svgToPngBlob: (svgString: string, options?: {
40
+ scale?: number;
41
+ }) => Promise<Blob>;
@@ -0,0 +1,12 @@
1
+ export declare const parseMarkdownIntoBlocks: (markdown: string) => string[];
2
+ export interface IncrementalParseState {
3
+ blocks: string[];
4
+ /** Tag-preprocessed markdown that produced `blocks` (before last-block remend). */
5
+ source: string;
6
+ }
7
+ /**
8
+ * Append-only parse for streaming: keep settled prefix blocks by identity and
9
+ * only re-lex the unfinished tail. Falls back to a full parse when the source
10
+ * is not a pure append (edits, rewinds, or structural shifts).
11
+ */
12
+ export declare const parseMarkdownIntoBlocksIncremental: (markdown: string, prev: IncrementalParseState | null | undefined, parseFn?: (value: string) => string[]) => IncrementalParseState;
@@ -0,0 +1,29 @@
1
+ import type { PluginConfig } from "./plugin-types";
2
+ /**
3
+ * Context for Streamdown plugins
4
+ */
5
+ export declare const PluginContext: import("react").Context<PluginConfig | null>;
6
+ /**
7
+ * Hook to access all plugins
8
+ */
9
+ export declare const usePlugins: () => PluginConfig | null;
10
+ /**
11
+ * Hook to access the code plugin
12
+ */
13
+ export declare const useCodePlugin: () => import("./plugin-types").CodeHighlighterPlugin | null;
14
+ /**
15
+ * Hook to access the mermaid plugin
16
+ */
17
+ export declare const useMermaidPlugin: () => import("./plugin-types").DiagramPlugin | null;
18
+ /**
19
+ * Hook to access the math plugin
20
+ */
21
+ export declare const useMathPlugin: () => import("./plugin-types").MathPlugin | null;
22
+ /**
23
+ * Hook to access the cjk plugin
24
+ */
25
+ export declare const useCjkPlugin: () => import("./plugin-types").CjkPlugin | null;
26
+ /**
27
+ * Hook to find a custom renderer for a given language
28
+ */
29
+ export declare const useCustomRenderer: (language: string) => import("./plugin-types").CustomRenderer | null;
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Structural type for Mermaid configuration.
3
+ * Avoids a hard dependency on the "mermaid" package in the core bundle.
4
+ * Users who need full type safety can import MermaidConfig from "mermaid"
5
+ * directly — it is structurally compatible with this type.
6
+ */
7
+ export type MermaidConfig = Record<string, any>;
8
+ import type React from "react";
9
+ import type { BundledLanguage, BundledTheme, ThemeRegistrationAny } from "shiki";
10
+ import type { Pluggable } from "unified";
11
+ export type ThemeInput = BundledTheme | ThemeRegistrationAny;
12
+ /**
13
+ * A single token in a highlighted line
14
+ */
15
+ export interface HighlightToken {
16
+ bgColor?: string;
17
+ color?: string;
18
+ content: string;
19
+ htmlAttrs?: Record<string, string>;
20
+ htmlStyle?: Record<string, string>;
21
+ offset?: number;
22
+ }
23
+ /**
24
+ * Result from code highlighting (compatible with shiki's TokensResult)
25
+ */
26
+ export interface HighlightResult {
27
+ bg?: string;
28
+ fg?: string;
29
+ rootStyle?: string | false;
30
+ tokens: HighlightToken[][];
31
+ }
32
+ /**
33
+ * Options for highlighting code
34
+ */
35
+ export interface HighlightOptions {
36
+ code: string;
37
+ language: BundledLanguage;
38
+ themes: [ThemeInput, ThemeInput];
39
+ }
40
+ /**
41
+ * Plugin for code syntax highlighting (Shiki)
42
+ */
43
+ export interface CodeHighlighterPlugin {
44
+ /**
45
+ * Get list of supported languages
46
+ */
47
+ getSupportedLanguages: () => BundledLanguage[];
48
+ /**
49
+ * Get the configured themes
50
+ */
51
+ getThemes: () => [ThemeInput, ThemeInput];
52
+ /**
53
+ * Highlight code and return tokens
54
+ * Returns null if highlighting not ready yet (async loading)
55
+ * Use callback for async result
56
+ */
57
+ highlight: (options: HighlightOptions, callback?: (result: HighlightResult) => void) => HighlightResult | null;
58
+ name: "shiki";
59
+ /**
60
+ * Check if language is supported
61
+ */
62
+ supportsLanguage: (language: BundledLanguage) => boolean;
63
+ type: "code-highlighter";
64
+ }
65
+ /**
66
+ * Mermaid instance interface
67
+ */
68
+ export interface MermaidInstance {
69
+ initialize: (config: MermaidConfig) => void;
70
+ render: (id: string, source: string) => Promise<{
71
+ svg: string;
72
+ }>;
73
+ }
74
+ /**
75
+ * Plugin for diagram rendering (Mermaid)
76
+ */
77
+ export interface DiagramPlugin {
78
+ /**
79
+ * Get the mermaid instance (initialized with optional config)
80
+ */
81
+ getMermaid: (config?: MermaidConfig) => MermaidInstance;
82
+ /**
83
+ * Language identifier for code blocks
84
+ */
85
+ language: string;
86
+ name: "mermaid";
87
+ type: "diagram";
88
+ }
89
+ /**
90
+ * Plugin for math rendering (KaTeX)
91
+ */
92
+ export interface MathPlugin {
93
+ /**
94
+ * Get CSS styles for math rendering (injected into head)
95
+ */
96
+ getStyles?: () => string;
97
+ name: "katex";
98
+ /**
99
+ * Get rehype plugin for rendering math
100
+ */
101
+ rehypePlugin: Pluggable;
102
+ /**
103
+ * Get remark plugin for parsing math syntax
104
+ */
105
+ remarkPlugin: Pluggable;
106
+ type: "math";
107
+ }
108
+ /**
109
+ * Plugin for CJK text handling
110
+ */
111
+ export interface CjkPlugin {
112
+ name: "cjk";
113
+ /**
114
+ * @deprecated Use remarkPluginsBefore and remarkPluginsAfter instead
115
+ * All remark plugins (for backwards compatibility)
116
+ */
117
+ remarkPlugins: Pluggable[];
118
+ /**
119
+ * Remark plugins that must run AFTER remarkGfm
120
+ * (e.g., autolink boundary splitting, strikethrough enhancements)
121
+ */
122
+ remarkPluginsAfter: Pluggable[];
123
+ /**
124
+ * Remark plugins that must run BEFORE remarkGfm
125
+ * (e.g., remark-cjk-friendly which modifies emphasis handling)
126
+ */
127
+ remarkPluginsBefore: Pluggable[];
128
+ type: "cjk";
129
+ }
130
+ /**
131
+ * Union type for all plugins
132
+ */
133
+ export type StreamdownPlugin = CodeHighlighterPlugin | DiagramPlugin | MathPlugin | CjkPlugin;
134
+ export interface CustomRendererProps {
135
+ code: string;
136
+ isIncomplete: boolean;
137
+ language: string;
138
+ /** Raw metastring from the code fence (everything after the language identifier).
139
+ * e.g. ```rust {1} title="foo" → meta = '{1} title="foo"'
140
+ * Undefined when no metastring is present. */
141
+ meta?: string;
142
+ }
143
+ export interface CustomRenderer {
144
+ component: React.ComponentType<CustomRendererProps>;
145
+ language: string | string[];
146
+ }
147
+ /**
148
+ * Plugin configuration passed to Streamdown
149
+ */
150
+ export interface PluginConfig {
151
+ cjk?: CjkPlugin;
152
+ code?: CodeHighlighterPlugin;
153
+ math?: MathPlugin;
154
+ mermaid?: DiagramPlugin;
155
+ renderers?: CustomRenderer[];
156
+ }
@@ -0,0 +1,12 @@
1
+ import { type CnFunction } from "./utils";
2
+ /**
3
+ * Context for providing a prefix-aware `cn` function to all components.
4
+ * Defaults to the standard `cn` (no prefix) for zero-overhead when unused.
5
+ */
6
+ export declare const PrefixContext: import("react").Context<CnFunction>;
7
+ /**
8
+ * Hook to access the prefix-aware `cn` function.
9
+ * When a prefix is set via `<Streamdown prefix="...">`, this returns
10
+ * a `cn` that prepends the prefix to all class names.
11
+ */
12
+ export declare const useCn: () => CnFunction;
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Preprocesses markdown to prevent custom tag blocks from being broken apart
3
+ * by the CommonMark parser. Two issues are addressed:
4
+ *
5
+ * 1. **Inline content after opening tag**: In CommonMark, HTML block types 6/7
6
+ * require the opening tag to start a line on its own (or be followed only by
7
+ * whitespace). When content appears on the same line as the opening tag
8
+ * (e.g. `<custom>content`), the parser treats it as inline HTML inside a
9
+ * paragraph instead of an HTML block, causing the tag to lose its structure.
10
+ * This function ensures the opening tag, content, and closing tag each
11
+ * occupy their own lines.
12
+ *
13
+ * 2. **Blank lines inside tag content**: HTML blocks end at blank lines, which
14
+ * causes custom tags with blank lines in their content to be split across
15
+ * multiple tokens. This function replaces blank lines within matched custom
16
+ * tag pairs with HTML comments (`<!---->`), so the markdown parser treats
17
+ * the entire tag block as a single unit.
18
+ */
19
+ export declare const preprocessCustomTags: (markdown: string, tagNames: string[]) => string;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Escapes markdown metacharacters inside the content of specified custom tags,
3
+ * so that markdown inside those tags is rendered as plain text rather than
4
+ * being interpreted as formatting.
5
+ *
6
+ * This must run BEFORE the markdown parser sees the string, because by the time
7
+ * rehype plugins execute the markdown has already been parsed and structural
8
+ * information (e.g. underscores around emphasis) is lost.
9
+ *
10
+ * Note: content that already contains backslash escapes (e.g. `\_`) will be
11
+ * double-escaped and render with a visible backslash. This is acceptable since
12
+ * the intended use case is raw data labels (usernames, handles) that should
13
+ * not contain markdown escape sequences.
14
+ *
15
+ * Example:
16
+ * Input: `<mention user_id="123">_some_username_</mention>`
17
+ * Output: `<mention user_id="123">\_some\_username\_</mention>`
18
+ * Rendered: literal `_some_username_`
19
+ */
20
+ /**
21
+ * For each tag in `tagNames`, escapes markdown metacharacters inside the tag's
22
+ * content so that the parser treats the children as plain text.
23
+ */
24
+ export declare const preprocessLiteralTagContent: (markdown: string, tagNames: string[]) => string;
@@ -0,0 +1,12 @@
1
+ import type { Root } from "hast";
2
+ import type { Plugin } from "unified";
3
+ /**
4
+ * rehype plugin — replaces children of elements whose tag names are in
5
+ * `tagNames` with a single plain-text node. Run this after rehype-raw and
6
+ * rehype-sanitize so the custom elements already exist as proper HAST nodes.
7
+ *
8
+ * Works in tandem with `preprocessLiteralTagContent`, which escapes markdown
9
+ * syntax before remark parses it, ensuring the text value here reflects the
10
+ * original literal content (not stripped markdown markers).
11
+ */
12
+ export declare const rehypeLiteralTagContent: Plugin<[string[]], Root>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * rehype plugin — re-parses text content of custom tag elements as Markdown.
3
+ *
4
+ * When a custom tag contains multiline content (e.g. `<ai-thinking>\n**bold**</ai-thinking>`),
5
+ * the CommonMark parser treats the entire block as an HTML block, passing the
6
+ * inner content through as raw text rather than parsing it as Markdown. This
7
+ * plugin corrects that by finding affected elements and replacing their
8
+ * text-only children with a proper Markdown-parsed HAST subtree.
9
+ *
10
+ * Runs after rehype-raw and rehype-sanitize so that custom elements already
11
+ * exist as proper HAST nodes. Must NOT be applied to tags listed in
12
+ * `literalTagContent` (those intentionally suppress Markdown parsing).
13
+ */
14
+ import type { Root } from "hast";
15
+ import type { Plugin } from "unified";
16
+ export declare const rehypeMarkdownInCustomTags: Plugin<[string[], string[]?], Root>;
@@ -0,0 +1,9 @@
1
+ import type { Root } from "mdast";
2
+ import type { Plugin } from "unified";
3
+ /**
4
+ * Remark plugin that forwards code fence meta strings to hast properties.
5
+ * This makes the meta string available as a `metastring` prop to the custom
6
+ * code component, enabling features like custom starting line numbers
7
+ * (e.g. `startLine=10`).
8
+ */
9
+ export declare const remarkCodeMeta: Plugin<[], Root>;