@lofcz/streamdown 2.9.1 → 2.9.3

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 +10 -6
  51. package/dist/lib/tailwind-classes.js +2 -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 +9 -6
  56. package/styles.css +55 -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
package/dist/index.d.ts CHANGED
@@ -1,490 +1,36 @@
1
- import * as react from 'react';
2
- import react__default, { SVGProps, JSX, ComponentType, HTMLAttributes, ComponentProps } from 'react';
3
- import * as react_jsx_runtime from 'react/jsx-runtime';
4
- import { RemendOptions } from 'remend';
5
- import { Pluggable, PluggableList } from 'unified';
6
- import { Element, Parents } from 'hast';
7
- import { Options as Options$1 } from 'remark-rehype';
8
- import { BundledTheme, ThemeRegistrationAny, BundledLanguage } from 'shiki';
9
- export { BundledLanguage, BundledTheme, ThemeRegistrationAny } from 'shiki';
10
-
11
- /**
12
- * Shared cursor used to chain stagger delays across sibling blocks in a
13
- * single render pass. Create one instance per Streamdown component and
14
- * reset `cursor.current = 0` before each React render so that block 0
15
- * starts at index 0 and each subsequent block continues from where the
16
- * previous one left off.
17
- */
18
- interface AnimateCursor {
19
- current: number;
20
- }
21
- declare function createAnimateCursor(): AnimateCursor;
22
- interface AnimatePlugin {
23
- /**
24
- * Returns the total HAST text node character count from the last
25
- * rehype run, then resets to 0. Use this value as the argument to
26
- * setPrevContentLength on the next render.
27
- */
28
- getLastRenderCharCount: () => number;
29
- /**
30
- * Returns the number of newly-animated words from the last rehype run,
31
- * then resets to 0. Pass this value to setStartIndex() on the next
32
- * sibling block so its stagger delays chain after ours.
33
- */
34
- getLastRenderNewWordCount: () => number;
35
- name: "animate";
36
- rehypePlugin: Pluggable;
37
- /**
38
- * Enable or disable animation inside code/pre blocks.
39
- * When true, code block content will be animated incrementally
40
- * during streaming (useful for incomplete/unclosed code fences).
41
- */
42
- setAnimateCodeBlocks: (enabled: boolean) => void;
43
- /**
44
- * Set the number of HAST text characters from a previous render.
45
- * Characters up to this count will get duration=0ms, preventing
46
- * re-animation of already-visible content during streaming updates.
47
- */
48
- setPrevContentLength: (length: number) => void;
49
- /**
50
- * Set the animation word index to start from. Used when no shared
51
- * cursor is provided. Use the value returned by
52
- * getLastRenderNewWordCount() from the previous sibling block to
53
- * ensure that a new block's stagger delays begin after the previous
54
- * block's animation is still completing, preventing concurrent reveals.
55
- */
56
- setStartIndex: (index: number) => void;
57
- type: "animate";
58
- }
59
- interface AnimateOptions {
60
- animation?: "fadeIn" | "blurIn" | "slideUp" | (string & {});
61
- /**
62
- * Shared cursor for automatic cross-block stagger chaining. When
63
- * provided the plugin reads `cursor.current` as the start index and
64
- * increments it by the number of newly animated words after each run,
65
- * so sibling blocks automatically pick up where the previous one left
66
- * off without any manual `setStartIndex` calls.
67
- */
68
- cursor?: AnimateCursor;
69
- duration?: number;
70
- easing?: string;
71
- sep?: "word" | "char";
72
- stagger?: number;
73
- }
74
- declare function createAnimatePlugin(options?: AnimateOptions): AnimatePlugin;
75
-
76
- type IconComponent = React.ComponentType<SVGProps<SVGSVGElement> & {
77
- size?: number;
78
- }>;
79
- interface IconMap {
80
- CheckIcon: IconComponent;
81
- CopyIcon: IconComponent;
82
- DownloadIcon: IconComponent;
83
- ExternalLinkIcon: IconComponent;
84
- Loader2Icon: IconComponent;
85
- Maximize2Icon: IconComponent;
86
- RotateCcwIcon: IconComponent;
87
- XIcon: IconComponent;
88
- ZoomInIcon: IconComponent;
89
- ZoomOutIcon: IconComponent;
90
- }
91
-
92
- interface ExtraProps {
93
- node?: Element | undefined;
94
- }
95
- type AllowElement = (element: Readonly<Element>, index: number, parent: Readonly<Parents> | undefined) => boolean | null | undefined;
96
- type UrlTransform = (url: string, key: string, node: Readonly<Element>) => string | null | undefined;
97
- type Components = {
98
- [Key in keyof JSX.IntrinsicElements]?: ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> | keyof JSX.IntrinsicElements;
99
- } & {
100
- inlineCode?: ComponentType<JSX.IntrinsicElements["code"] & ExtraProps>;
101
- [key: string]: ComponentType<Record<string, unknown> & ExtraProps> | keyof JSX.IntrinsicElements | undefined;
102
- };
103
- interface Options {
104
- allowElement?: AllowElement;
105
- allowedElements?: readonly string[];
106
- children?: string;
107
- components?: Components;
108
- disallowedElements?: readonly string[];
109
- rehypePlugins?: PluggableList;
110
- remarkPlugins?: PluggableList;
111
- remarkRehypeOptions?: Readonly<Options$1>;
112
- skipHtml?: boolean;
113
- unwrapDisallowed?: boolean;
114
- urlTransform?: UrlTransform;
115
- }
116
- declare const defaultUrlTransform: UrlTransform;
117
-
118
- /**
119
- * Structural type for Mermaid configuration.
120
- * Avoids a hard dependency on the "mermaid" package in the core bundle.
121
- * Users who need full type safety can import MermaidConfig from "mermaid"
122
- * directly — it is structurally compatible with this type.
123
- */
124
- type MermaidConfig = Record<string, any>;
125
-
126
- type ThemeInput = BundledTheme | ThemeRegistrationAny;
127
- /**
128
- * A single token in a highlighted line
129
- */
130
- interface HighlightToken {
131
- bgColor?: string;
132
- color?: string;
133
- content: string;
134
- htmlAttrs?: Record<string, string>;
135
- htmlStyle?: Record<string, string>;
136
- offset?: number;
137
- }
138
- /**
139
- * Result from code highlighting (compatible with shiki's TokensResult)
140
- */
141
- interface HighlightResult {
142
- bg?: string;
143
- fg?: string;
144
- rootStyle?: string | false;
145
- tokens: HighlightToken[][];
146
- }
147
- /**
148
- * Options for highlighting code
149
- */
150
- interface HighlightOptions {
151
- code: string;
152
- language: BundledLanguage;
153
- themes: [ThemeInput, ThemeInput];
154
- }
155
- /**
156
- * Plugin for code syntax highlighting (Shiki)
157
- */
158
- interface CodeHighlighterPlugin {
159
- /**
160
- * Get list of supported languages
161
- */
162
- getSupportedLanguages: () => BundledLanguage[];
163
- /**
164
- * Get the configured themes
165
- */
166
- getThemes: () => [ThemeInput, ThemeInput];
167
- /**
168
- * Highlight code and return tokens
169
- * Returns null if highlighting not ready yet (async loading)
170
- * Use callback for async result
171
- */
172
- highlight: (options: HighlightOptions, callback?: (result: HighlightResult) => void) => HighlightResult | null;
173
- name: "shiki";
174
- /**
175
- * Check if language is supported
176
- */
177
- supportsLanguage: (language: BundledLanguage) => boolean;
178
- type: "code-highlighter";
179
- }
180
- /**
181
- * Mermaid instance interface
182
- */
183
- interface MermaidInstance {
184
- initialize: (config: MermaidConfig) => void;
185
- render: (id: string, source: string) => Promise<{
186
- svg: string;
187
- }>;
188
- }
189
- /**
190
- * Plugin for diagram rendering (Mermaid)
191
- */
192
- interface DiagramPlugin {
193
- /**
194
- * Get the mermaid instance (initialized with optional config)
195
- */
196
- getMermaid: (config?: MermaidConfig) => MermaidInstance;
197
- /**
198
- * Language identifier for code blocks
199
- */
200
- language: string;
201
- name: "mermaid";
202
- type: "diagram";
203
- }
204
- /**
205
- * Plugin for math rendering (KaTeX)
206
- */
207
- interface MathPlugin {
208
- /**
209
- * Get CSS styles for math rendering (injected into head)
210
- */
211
- getStyles?: () => string;
212
- name: "katex";
213
- /**
214
- * Get rehype plugin for rendering math
215
- */
216
- rehypePlugin: Pluggable;
217
- /**
218
- * Get remark plugin for parsing math syntax
219
- */
220
- remarkPlugin: Pluggable;
221
- type: "math";
222
- }
223
- /**
224
- * Plugin for CJK text handling
225
- */
226
- interface CjkPlugin {
227
- name: "cjk";
228
- /**
229
- * @deprecated Use remarkPluginsBefore and remarkPluginsAfter instead
230
- * All remark plugins (for backwards compatibility)
231
- */
232
- remarkPlugins: Pluggable[];
233
- /**
234
- * Remark plugins that must run AFTER remarkGfm
235
- * (e.g., autolink boundary splitting, strikethrough enhancements)
236
- */
237
- remarkPluginsAfter: Pluggable[];
238
- /**
239
- * Remark plugins that must run BEFORE remarkGfm
240
- * (e.g., remark-cjk-friendly which modifies emphasis handling)
241
- */
242
- remarkPluginsBefore: Pluggable[];
243
- type: "cjk";
244
- }
245
- interface CustomRendererProps {
246
- code: string;
247
- isIncomplete: boolean;
248
- language: string;
249
- /** Raw metastring from the code fence (everything after the language identifier).
250
- * e.g. ```rust {1} title="foo" → meta = '{1} title="foo"'
251
- * Undefined when no metastring is present. */
252
- meta?: string;
253
- }
254
- interface CustomRenderer {
255
- component: react__default.ComponentType<CustomRendererProps>;
256
- language: string | string[];
257
- }
258
- /**
259
- * Plugin configuration passed to Streamdown
260
- */
261
- interface PluginConfig {
262
- cjk?: CjkPlugin;
263
- code?: CodeHighlighterPlugin;
264
- math?: MathPlugin;
265
- mermaid?: DiagramPlugin;
266
- renderers?: CustomRenderer[];
267
- }
268
-
269
- type ControlsConfig = boolean | {
270
- table?: boolean | {
271
- copy?: boolean;
272
- download?: boolean;
273
- fullscreen?: boolean;
274
- };
275
- code?: boolean | {
276
- copy?: boolean;
277
- download?: boolean;
278
- };
279
- mermaid?: boolean | {
280
- download?: boolean;
281
- copy?: boolean;
282
- fullscreen?: boolean;
283
- panZoom?: boolean;
284
- };
285
- image?: boolean | {
286
- download?: boolean;
287
- fullscreen?: boolean;
288
- };
289
- };
290
- interface LinkSafetyModalProps {
291
- isOpen: boolean;
292
- onClose: () => void;
293
- onConfirm: () => void;
294
- url: string;
295
- }
296
- interface LinkSafetyConfig {
297
- enabled: boolean;
298
- onLinkCheck?: (url: string) => Promise<boolean> | boolean;
299
- renderModal?: (props: LinkSafetyModalProps) => React.ReactNode;
300
- }
301
- interface MermaidErrorComponentProps {
302
- chart: string;
303
- error: string;
304
- retry: () => void;
305
- }
306
- interface MermaidOptions {
307
- config?: MermaidConfig;
308
- errorComponent?: React.ComponentType<MermaidErrorComponentProps>;
309
- }
310
- /**
311
- * Built-in list bullet style presets for nested unordered lists.
312
- * - `"flat"` — all levels use disc
313
- * - `"hierarchical"` — disc → circle → square, cycling
314
- */
315
- type ListStylePreset = "flat" | "hierarchical";
316
- interface StreamdownContextType {
317
- /** Max height for code blocks (px number or CSS length). `0` / `Infinity` disables. @default 400 */
318
- codeBlockMaxHeight?: number | string;
319
- controls: ControlsConfig;
320
- isAnimating: boolean;
321
- /** Show line numbers in code blocks. @default true */
322
- lineNumbers: boolean;
323
- linkSafety?: LinkSafetyConfig;
324
- /** Bullet style cycling for nested unordered lists. @default "hierarchical" */
325
- listStyle: ListStylePreset;
326
- mermaid?: MermaidOptions;
327
- mode: "static" | "streaming";
328
- shikiTheme: [ThemeInput, ThemeInput];
329
- /** Max height for tables (px number or CSS length). `0` / `Infinity` disables. @default 300 */
330
- tableMaxHeight?: number | string;
331
- }
332
- declare const StreamdownContext: react.Context<StreamdownContextType>;
333
-
334
- interface StreamdownTranslations {
335
- alertCaution: string;
336
- alertImportant: string;
337
- alertNote: string;
338
- alertTip: string;
339
- alertWarning: string;
340
- close: string;
341
- copied: string;
342
- copyCode: string;
343
- copyLink: string;
344
- copyTable: string;
345
- copyTableAsCsv: string;
346
- copyTableAsMarkdown: string;
347
- copyTableAsTsv: string;
348
- downloadDiagram: string;
349
- downloadDiagramAsMmd: string;
350
- downloadDiagramAsPng: string;
351
- downloadDiagramAsSvg: string;
352
- downloadFile: string;
353
- downloadImage: string;
354
- downloadTable: string;
355
- downloadTableAsCsv: string;
356
- downloadTableAsMarkdown: string;
357
- exitFullscreen: string;
358
- externalLinkWarning: string;
359
- imageNotAvailable: string;
360
- mermaidFormatMmd: string;
361
- mermaidFormatPng: string;
362
- mermaidFormatSvg: string;
363
- openExternalLink: string;
364
- openLink: string;
365
- tableFormatCsv: string;
366
- tableFormatMarkdown: string;
367
- tableFormatTsv: string;
368
- viewFullscreen: string;
369
- }
370
- declare const defaultTranslations: StreamdownTranslations;
371
-
372
- /**
373
- * Hook to check if the current block has an incomplete (unclosed) code fence.
374
- *
375
- * Returns `true` when the code fence in this block is still being streamed.
376
- * Useful for deferring expensive renders (syntax highlighting, Mermaid diagrams)
377
- * until the code block is complete.
378
- */
379
- declare const useIsCodeFenceIncomplete: () => boolean;
380
-
381
- type CodeBlockProps = HTMLAttributes<HTMLDivElement> & {
382
- code: string;
383
- language: string;
384
- /** Whether the code block is still being streamed (incomplete) */
385
- isIncomplete?: boolean;
386
- /** Custom starting line number for line numbering (default: 1) */
387
- startLine?: number;
388
- /** Show line numbers in code blocks. @default true */
389
- lineNumbers?: boolean;
390
- };
391
- declare const CodeBlock: ({ code, language, className, children, isIncomplete, startLine, lineNumbers, ...rest }: CodeBlockProps) => react_jsx_runtime.JSX.Element;
392
-
393
- type CodeBlockContainerProps = ComponentProps<"div"> & {
394
- language: string;
395
- /** Whether the code block is still being streamed (incomplete) */
396
- isIncomplete?: boolean;
397
- };
398
- declare const CodeBlockContainer: ({ className, language, style, isIncomplete, ...props }: CodeBlockContainerProps) => react_jsx_runtime.JSX.Element;
399
-
400
- type CodeBlockCopyButtonProps = ComponentProps<"button"> & {
401
- onCopy?: () => void;
402
- onError?: (error: Error) => void;
403
- timeout?: number;
404
- };
405
- declare const CodeBlockCopyButton: ({ onCopy, onError, timeout, children, className, code: propCode, ...props }: CodeBlockCopyButtonProps & {
406
- code?: string;
407
- }) => react_jsx_runtime.JSX.Element;
408
-
409
- type CodeBlockDownloadButtonProps = ComponentProps<"button"> & {
410
- onDownload?: () => void;
411
- onError?: (error: Error) => void;
412
- };
413
- declare const CodeBlockDownloadButton: ({ onDownload, onError, language, children, className, code: propCode, ...props }: CodeBlockDownloadButtonProps & {
414
- code?: string;
415
- language?: string;
416
- }) => react_jsx_runtime.JSX.Element;
417
-
418
- interface CodeBlockHeaderProps {
419
- language: string;
420
- }
421
- declare const CodeBlockHeader: ({ language }: CodeBlockHeaderProps) => react_jsx_runtime.JSX.Element;
422
-
423
- declare const CodeBlockSkeleton: () => react_jsx_runtime.JSX.Element;
424
-
425
- /**
426
- * Detect text direction using the "first strong character" algorithm.
427
- * Strips common markdown syntax then finds the first Unicode letter
428
- * with strong directionality.
429
- *
430
- * Note: markdown stripping is best-effort — nested formatting,
431
- * multi-line fenced code blocks, and raw HTML are not fully handled.
432
- * This is acceptable since the algorithm only needs to reach the first
433
- * strong character, which is almost always in plain prose.
434
- *
435
- * @returns "rtl" if first strong char is RTL, "ltr" otherwise
436
- */
437
- declare function detectTextDirection(text: string): "ltr" | "rtl";
438
-
439
- declare const parseMarkdownIntoBlocks: (markdown: string) => string[];
440
- interface IncrementalParseState {
441
- blocks: string[];
442
- /** Tag-preprocessed markdown that produced `blocks` (before last-block remend). */
443
- source: string;
444
- }
445
- /**
446
- * Append-only parse for streaming: keep settled prefix blocks by identity and
447
- * only re-lex the unfinished tail. Falls back to a full parse when the source
448
- * is not a pure append (edits, rewinds, or structural shifts).
449
- */
450
- declare const parseMarkdownIntoBlocksIncremental: (markdown: string, prev: IncrementalParseState | null | undefined, parseFn?: (value: string) => string[]) => IncrementalParseState;
451
-
452
- interface TableCopyDropdownProps {
453
- children?: React.ReactNode;
454
- className?: string;
455
- onCopy?: (format: "csv" | "tsv" | "md") => void;
456
- onError?: (error: Error) => void;
457
- timeout?: number;
458
- }
459
- declare const TableCopyDropdown: ({ children, className, onCopy, onError, timeout, }: TableCopyDropdownProps) => react_jsx_runtime.JSX.Element;
460
-
461
- interface TableDownloadButtonProps {
462
- children?: React.ReactNode;
463
- className?: string;
464
- filename?: string;
465
- format?: "csv" | "markdown";
466
- onDownload?: () => void;
467
- onError?: (error: Error) => void;
468
- }
469
- declare const TableDownloadButton: ({ children, className, onDownload, onError, format, filename, }: TableDownloadButtonProps) => react_jsx_runtime.JSX.Element;
470
- interface TableDownloadDropdownProps {
471
- children?: React.ReactNode;
472
- className?: string;
473
- onDownload?: (format: "csv" | "markdown") => void;
474
- onError?: (error: Error) => void;
475
- }
476
- declare const TableDownloadDropdown: ({ children, className, onDownload, onError, }: TableDownloadDropdownProps) => react_jsx_runtime.JSX.Element;
477
-
478
- interface TableData {
479
- headers: string[];
480
- rows: string[][];
481
- }
482
- declare const extractTableDataFromElement: (tableElement: HTMLElement) => TableData;
483
- declare const tableDataToCSV: (data: TableData) => string;
484
- declare const tableDataToTSV: (data: TableData) => string;
485
- declare const escapeMarkdownTableCell: (cell: string) => string;
486
- declare const tableDataToMarkdown: (data: TableData) => string;
487
-
1
+ import { type RemendOptions } from "remend";
2
+ import type { Pluggable } from "unified";
3
+ import { type AnimateOptions, type AnimatePlugin } from "./lib/animate";
4
+ import { type IconMap } from "./lib/icon-context";
5
+ import { type Options } from "./lib/markdown";
6
+ import type { PluginConfig, ThemeInput } from "./lib/plugin-types";
7
+ import { type CalloutIconResolver, type CalloutStyleResolver, type ControlsConfig, type LinkSafetyConfig, type ListStylePreset, type MermaidOptions, type ScrollableComponent } from "./lib/streamdown-context";
8
+ import { type StreamdownTranslations } from "./lib/translations-context";
9
+ export type { BundledLanguage, BundledTheme, ThemeRegistrationAny, } from "shiki";
10
+ export type { AnimateOptions } from "./lib/animate";
11
+ export { createAnimateCursor, createAnimatePlugin } from "./lib/animate";
12
+ export { useIsCodeFenceIncomplete } from "./lib/block-incomplete-context";
13
+ export { CodeBlock } from "./lib/code-block";
14
+ export { CodeBlockContainer } from "./lib/code-block/container";
15
+ export { CodeBlockCopyButton } from "./lib/code-block/copy-button";
16
+ export { CodeBlockDownloadButton } from "./lib/code-block/download-button";
17
+ export { CodeBlockHeader } from "./lib/code-block/header";
18
+ export { CodeBlockSkeleton } from "./lib/code-block/skeleton";
19
+ export { detectTextDirection } from "./lib/detect-direction";
20
+ export type { IconMap } from "./lib/icon-context";
21
+ export type { AllowElement, Components, ExtraProps, UrlTransform, } from "./lib/markdown";
22
+ export { defaultUrlTransform } from "./lib/markdown";
23
+ export type { IncrementalParseState } from "./lib/parse-blocks";
24
+ export { parseMarkdownIntoBlocks, parseMarkdownIntoBlocksIncremental, } from "./lib/parse-blocks";
25
+ export type { CjkPlugin, CodeHighlighterPlugin, CustomRenderer, CustomRendererProps, DiagramPlugin, HighlightOptions, MathPlugin, PluginConfig, ThemeInput, } from "./lib/plugin-types";
26
+ export { DefaultScrollable } from "./lib/scrollable";
27
+ export type { CalloutIconResolver, CalloutStyleResolver, ControlsConfig, LinkSafetyConfig, LinkSafetyModalProps, MermaidErrorComponentProps, MermaidOptions, ScrollableComponent, ScrollableProps, StreamdownContextType, } from "./lib/streamdown-context";
28
+ export { StreamdownContext } from "./lib/streamdown-context";
29
+ export { TableCopyDropdown, type TableCopyDropdownProps, } from "./lib/table/copy-dropdown";
30
+ export { TableDownloadButton, type TableDownloadButtonProps, TableDownloadDropdown, type TableDownloadDropdownProps, } from "./lib/table/download-dropdown";
31
+ export { escapeMarkdownTableCell, extractTableDataFromElement, type TableData, tableDataToCSV, tableDataToMarkdown, tableDataToTSV, } from "./lib/table/utils";
32
+ export type { StreamdownTranslations } from "./lib/translations-context";
33
+ export { defaultTranslations } from "./lib/translations-context";
488
34
  /**
489
35
  * Normalizes indentation in HTML blocks to prevent Markdown parsers from
490
36
  * treating indented HTML tags as code blocks (4+ spaces = code in Markdown).
@@ -495,9 +41,9 @@ declare const tableDataToMarkdown: (data: TableData) => string;
495
41
  * @param content - The raw HTML/Markdown string to normalize
496
42
  * @returns The normalized string with reduced indentation before HTML tags
497
43
  */
498
- declare const normalizeHtmlIndentation: (content: string) => string;
499
- type AllowedTags = Record<string, string[]>;
500
- type StreamdownProps = Options & {
44
+ export declare const normalizeHtmlIndentation: (content: string) => string;
45
+ export type AllowedTags = Record<string, string[]>;
46
+ export type StreamdownProps = Options & {
501
47
  mode?: "static" | "streaming";
502
48
  /** Text direction for blocks. "auto" detects per-block using first strong character algorithm. */
503
49
  dir?: "auto" | "ltr" | "rtl";
@@ -512,11 +58,17 @@ type StreamdownProps = Options & {
512
58
  codeBlockMaxHeight?: number | string;
513
59
  controls?: ControlsConfig;
514
60
  isAnimating?: boolean;
61
+ /** Component used for horizontal-scroll regions (code body, table). Defaults to a plain div — override to plug in a custom scrollbar (e.g. OverlayScrollbars) declaratively. */
62
+ scrollable?: ScrollableComponent;
515
63
  tableMaxHeight?: number | string;
516
64
  animated?: boolean | AnimateOptions;
517
65
  caret?: keyof typeof carets;
518
66
  /** Bullet style cycling for nested unordered lists. @default "hierarchical" */
519
67
  listStyle?: ListStylePreset;
68
+ /** Icon resolver for custom callouts (`>>> (icon)[Title]{color}`). Return null/undefined for a blank placeholder. */
69
+ calloutIcon?: CalloutIconResolver;
70
+ /** Style resolver for custom callouts — computes the tinted background + accent border/title color. */
71
+ calloutStyle?: CalloutStyleResolver;
520
72
  plugins?: PluginConfig;
521
73
  remend?: RemendOptions;
522
74
  linkSafety?: LinkSafetyConfig;
@@ -551,14 +103,19 @@ type StreamdownProps = Options & {
551
103
  /** Called when isAnimating transitions from true to false. Suppressed in mode="static". */
552
104
  onAnimationEnd?: () => void;
553
105
  };
554
- declare const defaultRehypePlugins: Record<string, Pluggable>;
555
- declare const defaultRemarkPlugins: Record<string, Pluggable>;
106
+ export declare const defaultRehypePlugins: Record<string, Pluggable>;
107
+ export declare const defaultRemarkPlugins: Record<string, Pluggable>;
556
108
  declare const carets: {
557
109
  block: string;
558
110
  circle: string;
559
111
  };
560
-
561
- type BlockProps = Options & {
112
+ /**
113
+ * Built-in list bullet style presets for nested unordered lists.
114
+ * - `"flat"` — all levels use disc
115
+ * - `"hierarchical"` — disc → circle → square, cycling
116
+ */
117
+ export type { ListStylePreset } from "./lib/streamdown-context";
118
+ export type BlockProps = Options & {
562
119
  content: string;
563
120
  shouldParseIncompleteMarkdown: boolean;
564
121
  shouldNormalizeHtmlIndentation: boolean;
@@ -570,7 +127,5 @@ type BlockProps = Options & {
570
127
  /** Animate plugin instance for tracking previous content length */
571
128
  animatePlugin?: AnimatePlugin | null;
572
129
  };
573
- declare const Block: react.MemoExoticComponent<({ content, shouldParseIncompleteMarkdown: _, shouldNormalizeHtmlIndentation, index: __, isIncomplete, dir, animatePlugin: animatePluginProp, ...props }: BlockProps) => react_jsx_runtime.JSX.Element>;
574
- declare const Streamdown: react.MemoExoticComponent<({ children, mode, dir, parseIncompleteMarkdown: shouldParseIncompleteMarkdown, normalizeHtmlIndentation: shouldNormalizeHtmlIndentation, components, rehypePlugins, remarkPlugins, className, shikiTheme, mermaid, codeBlockMaxHeight, controls, isAnimating, tableMaxHeight, animated, BlockComponent, parseMarkdownIntoBlocksFn, caret, listStyle, plugins, remend: remendOptions, linkSafety, lineNumbers, allowedTags, literalTagContent, translations, icons: iconOverrides, prefix, onAnimationStart, onAnimationEnd, ...props }: StreamdownProps) => react_jsx_runtime.JSX.Element>;
575
-
576
- export { type AllowElement, type AllowedTags, type AnimateOptions, Block, type BlockProps, type CjkPlugin, CodeBlock, CodeBlockContainer, CodeBlockCopyButton, CodeBlockDownloadButton, CodeBlockHeader, CodeBlockSkeleton, type CodeHighlighterPlugin, type Components, type ControlsConfig, type CustomRenderer, type CustomRendererProps, type DiagramPlugin, type ExtraProps, type HighlightOptions, type IconMap, type IncrementalParseState, type LinkSafetyConfig, type LinkSafetyModalProps, type ListStylePreset, type MathPlugin, type MermaidErrorComponentProps, type MermaidOptions, type PluginConfig, Streamdown, StreamdownContext, type StreamdownContextType, type StreamdownProps, type StreamdownTranslations, TableCopyDropdown, type TableCopyDropdownProps, type TableData, TableDownloadButton, type TableDownloadButtonProps, TableDownloadDropdown, type TableDownloadDropdownProps, type ThemeInput, type UrlTransform, createAnimateCursor, createAnimatePlugin, defaultRehypePlugins, defaultRemarkPlugins, defaultTranslations, defaultUrlTransform, detectTextDirection, escapeMarkdownTableCell, extractTableDataFromElement, normalizeHtmlIndentation, parseMarkdownIntoBlocks, parseMarkdownIntoBlocksIncremental, tableDataToCSV, tableDataToMarkdown, tableDataToTSV, useIsCodeFenceIncomplete };
130
+ export declare const Block: import("react").MemoExoticComponent<({ content, shouldParseIncompleteMarkdown: _, shouldNormalizeHtmlIndentation, index: __, isIncomplete, dir, animatePlugin: animatePluginProp, ...props }: BlockProps) => import("react/jsx-runtime").JSX.Element>;
131
+ export declare const Streamdown: import("react").MemoExoticComponent<({ children, mode, dir, parseIncompleteMarkdown: shouldParseIncompleteMarkdown, normalizeHtmlIndentation: shouldNormalizeHtmlIndentation, components, rehypePlugins, remarkPlugins, className, shikiTheme, mermaid, codeBlockMaxHeight, controls, isAnimating, scrollable, tableMaxHeight, animated, BlockComponent, parseMarkdownIntoBlocksFn, caret, listStyle, calloutIcon, calloutStyle, plugins, remend: remendOptions, linkSafety, lineNumbers, allowedTags, literalTagContent, translations, icons: iconOverrides, prefix, onAnimationStart, onAnimationEnd, ...props }: StreamdownProps) => import("react/jsx-runtime").JSX.Element>;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  "use client";
2
- export{D as Block,h as CodeBlock,e as CodeBlockContainer,j as CodeBlockCopyButton,k as CodeBlockDownloadButton,f as CodeBlockHeader,l as CodeBlockSkeleton,E as Streamdown,m as StreamdownContext,t as TableCopyDropdown,u as TableDownloadButton,v as TableDownloadDropdown,a as createAnimateCursor,b as createAnimatePlugin,B as defaultRehypePlugins,C as defaultRemarkPlugins,i as defaultTranslations,x as defaultUrlTransform,w as detectTextDirection,r as escapeMarkdownTableCell,o as extractTableDataFromElement,A as normalizeHtmlIndentation,y as parseMarkdownIntoBlocks,z as parseMarkdownIntoBlocksIncremental,p as tableDataToCSV,s as tableDataToMarkdown,q as tableDataToTSV,c as useIsCodeFenceIncomplete}from'./chunk-WRHXGPDT.js';
2
+ export{E as Block,i as CodeBlock,f as CodeBlockContainer,k as CodeBlockCopyButton,l as CodeBlockDownloadButton,g as CodeBlockHeader,m as CodeBlockSkeleton,d as DefaultScrollable,F as Streamdown,n as StreamdownContext,v as TableCopyDropdown,w as TableDownloadButton,x as TableDownloadDropdown,a as createAnimateCursor,b as createAnimatePlugin,C as defaultRehypePlugins,D as defaultRemarkPlugins,j as defaultTranslations,o as defaultUrlTransform,y as detectTextDirection,t as escapeMarkdownTableCell,q as extractTableDataFromElement,B as normalizeHtmlIndentation,z as parseMarkdownIntoBlocks,A as parseMarkdownIntoBlocksIncremental,r as tableDataToCSV,u as tableDataToMarkdown,s as tableDataToTSV,c as useIsCodeFenceIncomplete}from'./chunk-NE4QKYRI.js';
@@ -0,0 +1,66 @@
1
+ import type { Pluggable } from "unified";
2
+ /**
3
+ * Shared cursor used to chain stagger delays across sibling blocks in a
4
+ * single render pass. Create one instance per Streamdown component and
5
+ * reset `cursor.current = 0` before each React render so that block 0
6
+ * starts at index 0 and each subsequent block continues from where the
7
+ * previous one left off.
8
+ */
9
+ export interface AnimateCursor {
10
+ current: number;
11
+ }
12
+ export declare function createAnimateCursor(): AnimateCursor;
13
+ export interface AnimatePlugin {
14
+ /**
15
+ * Returns the total HAST text node character count from the last
16
+ * rehype run, then resets to 0. Use this value as the argument to
17
+ * setPrevContentLength on the next render.
18
+ */
19
+ getLastRenderCharCount: () => number;
20
+ /**
21
+ * Returns the number of newly-animated words from the last rehype run,
22
+ * then resets to 0. Pass this value to setStartIndex() on the next
23
+ * sibling block so its stagger delays chain after ours.
24
+ */
25
+ getLastRenderNewWordCount: () => number;
26
+ name: "animate";
27
+ rehypePlugin: Pluggable;
28
+ /**
29
+ * Enable or disable animation inside code/pre blocks.
30
+ * When true, code block content will be animated incrementally
31
+ * during streaming (useful for incomplete/unclosed code fences).
32
+ */
33
+ setAnimateCodeBlocks: (enabled: boolean) => void;
34
+ /**
35
+ * Set the number of HAST text characters from a previous render.
36
+ * Characters up to this count will get duration=0ms, preventing
37
+ * re-animation of already-visible content during streaming updates.
38
+ */
39
+ setPrevContentLength: (length: number) => void;
40
+ /**
41
+ * Set the animation word index to start from. Used when no shared
42
+ * cursor is provided. Use the value returned by
43
+ * getLastRenderNewWordCount() from the previous sibling block to
44
+ * ensure that a new block's stagger delays begin after the previous
45
+ * block's animation is still completing, preventing concurrent reveals.
46
+ */
47
+ setStartIndex: (index: number) => void;
48
+ type: "animate";
49
+ }
50
+ export interface AnimateOptions {
51
+ animation?: "fadeIn" | "blurIn" | "slideUp" | (string & {});
52
+ /**
53
+ * Shared cursor for automatic cross-block stagger chaining. When
54
+ * provided the plugin reads `cursor.current` as the start index and
55
+ * increments it by the number of newly animated words after each run,
56
+ * so sibling blocks automatically pick up where the previous one left
57
+ * off without any manual `setStartIndex` calls.
58
+ */
59
+ cursor?: AnimateCursor;
60
+ duration?: number;
61
+ easing?: string;
62
+ sep?: "word" | "char";
63
+ stagger?: number;
64
+ }
65
+ export declare function createAnimatePlugin(options?: AnimateOptions): AnimatePlugin;
66
+ export declare const animate: AnimatePlugin;