@assistant-ui/react-streamdown 0.0.0
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.
- package/README.md +163 -0
- package/dist/adapters/PreOverride.d.ts +27 -0
- package/dist/adapters/PreOverride.d.ts.map +1 -0
- package/dist/adapters/PreOverride.js +31 -0
- package/dist/adapters/PreOverride.js.map +1 -0
- package/dist/adapters/code-adapter.d.ts +22 -0
- package/dist/adapters/code-adapter.d.ts.map +1 -0
- package/dist/adapters/code-adapter.js +75 -0
- package/dist/adapters/code-adapter.js.map +1 -0
- package/dist/adapters/components-adapter.d.ts +18 -0
- package/dist/adapters/components-adapter.d.ts.map +1 -0
- package/dist/adapters/components-adapter.js +34 -0
- package/dist/adapters/components-adapter.js.map +1 -0
- package/dist/defaults.d.ts +18 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +37 -0
- package/dist/defaults.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/memoization.d.ts +10 -0
- package/dist/memoization.d.ts.map +1 -0
- package/dist/memoization.js +30 -0
- package/dist/memoization.js.map +1 -0
- package/dist/primitives/StreamdownText.d.ts +60 -0
- package/dist/primitives/StreamdownText.d.ts.map +1 -0
- package/dist/primitives/StreamdownText.js +124 -0
- package/dist/primitives/StreamdownText.js.map +1 -0
- package/dist/types.d.ts +356 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +93 -0
- package/src/__tests__/PreOverride.test.tsx +132 -0
- package/src/__tests__/code-adapter.integration.test.tsx +325 -0
- package/src/__tests__/code-adapter.test.tsx +46 -0
- package/src/__tests__/components-adapter.test.tsx +152 -0
- package/src/__tests__/defaults.test.ts +96 -0
- package/src/__tests__/index.test.ts +40 -0
- package/src/__tests__/memoization.test.ts +71 -0
- package/src/adapters/PreOverride.tsx +52 -0
- package/src/adapters/code-adapter.tsx +148 -0
- package/src/adapters/components-adapter.tsx +51 -0
- package/src/defaults.ts +46 -0
- package/src/index.ts +45 -0
- package/src/memoization.ts +38 -0
- package/src/primitives/StreamdownText.tsx +201 -0
- package/src/types.ts +416 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @assistant-ui/react-streamdown
|
|
2
|
+
|
|
3
|
+
Streamdown-based markdown rendering for assistant-ui. An alternative to `@assistant-ui/react-markdown` with built-in syntax highlighting, math, and diagram support.
|
|
4
|
+
|
|
5
|
+
## When to Use
|
|
6
|
+
|
|
7
|
+
| Package | Best For |
|
|
8
|
+
|---------|----------|
|
|
9
|
+
| `@assistant-ui/react-markdown` | Lightweight, bring-your-own syntax highlighter |
|
|
10
|
+
| `@assistant-ui/react-streamdown` | Feature-rich with built-in Shiki, KaTeX, Mermaid |
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install @assistant-ui/react-streamdown streamdown
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
For additional features, install the optional plugins:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @streamdown/code @streamdown/math @streamdown/mermaid @streamdown/cjk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
### Basic
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { StreamdownTextPrimitive } from "@assistant-ui/react-streamdown";
|
|
30
|
+
|
|
31
|
+
// Inside a MessagePartText component
|
|
32
|
+
<StreamdownTextPrimitive />
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### With Plugins (Recommended)
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { StreamdownTextPrimitive } from "@assistant-ui/react-streamdown";
|
|
39
|
+
import { code } from "@streamdown/code";
|
|
40
|
+
import { math } from "@streamdown/math";
|
|
41
|
+
import { mermaid } from "@streamdown/mermaid";
|
|
42
|
+
import "katex/dist/katex.min.css";
|
|
43
|
+
|
|
44
|
+
<StreamdownTextPrimitive
|
|
45
|
+
plugins={{ code, math, mermaid }}
|
|
46
|
+
shikiTheme={["github-light", "github-dark"]}
|
|
47
|
+
/>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Migration from react-markdown
|
|
51
|
+
|
|
52
|
+
If you're migrating from `@assistant-ui/react-markdown`, you can use the compatibility API:
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
import { StreamdownTextPrimitive } from "@assistant-ui/react-streamdown";
|
|
56
|
+
|
|
57
|
+
// Your existing SyntaxHighlighter component still works
|
|
58
|
+
<StreamdownTextPrimitive
|
|
59
|
+
components={{
|
|
60
|
+
SyntaxHighlighter: MySyntaxHighlighter,
|
|
61
|
+
CodeHeader: MyCodeHeader,
|
|
62
|
+
}}
|
|
63
|
+
componentsByLanguage={{
|
|
64
|
+
mermaid: { SyntaxHighlighter: MermaidRenderer }
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Props
|
|
70
|
+
|
|
71
|
+
| Prop | Type | Description |
|
|
72
|
+
|------|------|-------------|
|
|
73
|
+
| `mode` | `"streaming" \| "static"` | Rendering mode. Default: `"streaming"` |
|
|
74
|
+
| `plugins` | `PluginConfig` | Streamdown plugins (code, math, mermaid, cjk) |
|
|
75
|
+
| `shikiTheme` | `[string, string]` | Light and dark theme for Shiki |
|
|
76
|
+
| `components` | `object` | Custom components including `SyntaxHighlighter` and `CodeHeader` |
|
|
77
|
+
| `componentsByLanguage` | `object` | Language-specific component overrides |
|
|
78
|
+
| `preprocess` | `(text: string) => string` | Text preprocessing function |
|
|
79
|
+
| `controls` | `boolean \| object` | Enable/disable UI controls for code blocks and tables |
|
|
80
|
+
| `containerProps` | `object` | Props for the container div |
|
|
81
|
+
| `containerClassName` | `string` | Class name for the container |
|
|
82
|
+
| `remarkRehypeOptions` | `object` | Options passed to remark-rehype during processing |
|
|
83
|
+
| `BlockComponent` | `React.ComponentType` | Custom component for rendering blocks |
|
|
84
|
+
| `parseMarkdownIntoBlocksFn` | `(md: string) => string[]` | Custom block parsing function |
|
|
85
|
+
| `remend` | `object` | Incomplete markdown auto-completion config |
|
|
86
|
+
| `linkSafety` | `object` | Link safety confirmation config |
|
|
87
|
+
| `mermaid` | `object` | Mermaid diagram rendering config |
|
|
88
|
+
| `allowedTags` | `object` | HTML tags whitelist |
|
|
89
|
+
|
|
90
|
+
## Differences from react-markdown
|
|
91
|
+
|
|
92
|
+
1. **Streaming optimization**: Uses block-based rendering and `remend` for better streaming performance
|
|
93
|
+
2. **Built-in highlighting**: Shiki is integrated via `@streamdown/code` plugin
|
|
94
|
+
3. **No smooth prop**: Streaming animation is handled by streamdown's `mode` and `isAnimating`
|
|
95
|
+
4. **Auto isAnimating**: Automatically detects streaming state from message context
|
|
96
|
+
|
|
97
|
+
## Advanced Usage
|
|
98
|
+
|
|
99
|
+
### Custom Block Rendering
|
|
100
|
+
|
|
101
|
+
Use `BlockComponent` to customize how individual markdown blocks are rendered:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<StreamdownTextPrimitive
|
|
105
|
+
BlockComponent={({ content, index }) => (
|
|
106
|
+
<div key={index} className="my-block">
|
|
107
|
+
{/* Custom block rendering */}
|
|
108
|
+
</div>
|
|
109
|
+
)}
|
|
110
|
+
/>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Custom Block Parsing
|
|
114
|
+
|
|
115
|
+
Override the default block splitting logic:
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
<StreamdownTextPrimitive
|
|
119
|
+
parseMarkdownIntoBlocksFn={(markdown) => markdown.split(/\n{2,}/)}
|
|
120
|
+
/>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Using Hooks
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
import {
|
|
127
|
+
useIsStreamdownCodeBlock,
|
|
128
|
+
useStreamdownPreProps,
|
|
129
|
+
} from "@assistant-ui/react-streamdown";
|
|
130
|
+
|
|
131
|
+
// Inside a code component
|
|
132
|
+
function MyCodeComponent() {
|
|
133
|
+
const isCodeBlock = useIsStreamdownCodeBlock();
|
|
134
|
+
const preProps = useStreamdownPreProps();
|
|
135
|
+
|
|
136
|
+
if (!isCodeBlock) {
|
|
137
|
+
return <code className="inline-code">...</code>;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return <pre {...preProps}>...</pre>;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Performance Best Practices
|
|
145
|
+
|
|
146
|
+
1. **Use memoized components**: Custom `SyntaxHighlighter` and `CodeHeader` components should be memoized to avoid unnecessary re-renders.
|
|
147
|
+
|
|
148
|
+
2. **Avoid inline function props**: Define `preprocess`, `parseMarkdownIntoBlocksFn`, and other callbacks outside the render function or wrap them in `useCallback`.
|
|
149
|
+
|
|
150
|
+
3. **Plugin configuration**: Pass plugin objects by reference (not inline) to prevent recreation on each render.
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
// Good
|
|
154
|
+
const plugins = useMemo(() => ({ code, math }), []);
|
|
155
|
+
<StreamdownTextPrimitive plugins={plugins} />
|
|
156
|
+
|
|
157
|
+
// Avoid
|
|
158
|
+
<StreamdownTextPrimitive plugins={{ code, math }} />
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Element } from "hast";
|
|
2
|
+
import { type ComponentPropsWithoutRef } from "react";
|
|
3
|
+
type PreOverrideProps = ComponentPropsWithoutRef<"pre"> & {
|
|
4
|
+
node?: Element | undefined;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Context that indicates we're inside a <pre> element (code block).
|
|
8
|
+
* Used by code adapter to distinguish inline code from block code.
|
|
9
|
+
*/
|
|
10
|
+
export declare const PreContext: import("react").Context<PreOverrideProps | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Hook to check if the current code element is inside a code block.
|
|
13
|
+
* Returns true if inside a <pre> (code block), false if inline code.
|
|
14
|
+
*/
|
|
15
|
+
export declare function useIsStreamdownCodeBlock(): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Hook to get the pre element props when inside a code block.
|
|
18
|
+
* Returns null if not inside a code block.
|
|
19
|
+
*/
|
|
20
|
+
export declare function useStreamdownPreProps(): PreOverrideProps | null;
|
|
21
|
+
/**
|
|
22
|
+
* Pre component override that provides context for child code elements.
|
|
23
|
+
* This enables reliable inline vs block code detection.
|
|
24
|
+
*/
|
|
25
|
+
export declare const PreOverride: import("react").NamedExoticComponent<PreOverrideProps>;
|
|
26
|
+
export {};
|
|
27
|
+
//# sourceMappingURL=PreOverride.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreOverride.d.ts","sourceRoot":"","sources":["../../src/adapters/PreOverride.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EACL,KAAK,wBAAwB,EAI9B,MAAM,OAAO,CAAC;AAGf,KAAK,gBAAgB,GAAG,wBAAwB,CAAC,KAAK,CAAC,GAAG;IACxD,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,UAAU,kDAA+C,CAAC;AAEvE;;;GAGG;AACH,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,gBAAgB,GAAG,IAAI,CAE/D;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,wDAUJ,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { createContext, memo, useContext, } from "react";
|
|
4
|
+
import { memoCompareNodes } from "../memoization.js";
|
|
5
|
+
/**
|
|
6
|
+
* Context that indicates we're inside a <pre> element (code block).
|
|
7
|
+
* Used by code adapter to distinguish inline code from block code.
|
|
8
|
+
*/
|
|
9
|
+
export const PreContext = createContext(null);
|
|
10
|
+
/**
|
|
11
|
+
* Hook to check if the current code element is inside a code block.
|
|
12
|
+
* Returns true if inside a <pre> (code block), false if inline code.
|
|
13
|
+
*/
|
|
14
|
+
export function useIsStreamdownCodeBlock() {
|
|
15
|
+
return useContext(PreContext) !== null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Hook to get the pre element props when inside a code block.
|
|
19
|
+
* Returns null if not inside a code block.
|
|
20
|
+
*/
|
|
21
|
+
export function useStreamdownPreProps() {
|
|
22
|
+
return useContext(PreContext);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Pre component override that provides context for child code elements.
|
|
26
|
+
* This enables reliable inline vs block code detection.
|
|
27
|
+
*/
|
|
28
|
+
export const PreOverride = memo(function PreOverride({ children, node, ...rest }) {
|
|
29
|
+
return (_jsx(PreContext.Provider, { value: { node, ...rest }, children: _jsx("pre", { ...rest, children: children }) }));
|
|
30
|
+
}, memoCompareNodes);
|
|
31
|
+
//# sourceMappingURL=PreOverride.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreOverride.js","sourceRoot":"","sources":["../../src/adapters/PreOverride.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAEL,aAAa,EACb,IAAI,EACJ,UAAU,GACX,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,gBAAgB,EAAE,0BAAuB;AAMlD;;;GAGG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAA0B,IAAI,CAAC,CAAC;AAEvE;;;GAGG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,UAAU,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,UAAU,CAAC,UAAU,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,WAAW,CAAC,EACnD,QAAQ,EACR,IAAI,EACJ,GAAG,IAAI,EACU;IACjB,OAAO,CACL,KAAC,UAAU,CAAC,QAAQ,IAAC,KAAK,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,YAC3C,iBAAS,IAAI,YAAG,QAAQ,GAAO,GACX,CACvB,CAAC;AACJ,CAAC,EAAE,gBAAgB,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Element } from "hast";
|
|
2
|
+
import { type ComponentPropsWithoutRef, type ComponentType } from "react";
|
|
3
|
+
import type { CodeHeaderProps, ComponentsByLanguage, SyntaxHighlighterProps } from "../types.js";
|
|
4
|
+
type CodeProps = ComponentPropsWithoutRef<"code"> & {
|
|
5
|
+
node?: Element | undefined;
|
|
6
|
+
};
|
|
7
|
+
interface CodeAdapterOptions {
|
|
8
|
+
SyntaxHighlighter?: ComponentType<SyntaxHighlighterProps> | undefined;
|
|
9
|
+
CodeHeader?: ComponentType<CodeHeaderProps> | undefined;
|
|
10
|
+
componentsByLanguage?: ComponentsByLanguage | undefined;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a code component adapter that bridges the assistant-ui
|
|
14
|
+
* SyntaxHighlighter/CodeHeader API to streamdown's code component.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createCodeAdapter(options: CodeAdapterOptions): import("react").MemoExoticComponent<({ node, className, children, ...props }: CodeProps) => import("react/jsx-runtime").JSX.Element | null>;
|
|
17
|
+
/**
|
|
18
|
+
* Checks if the code adapter should be used (i.e., user provided custom components).
|
|
19
|
+
*/
|
|
20
|
+
export declare function shouldUseCodeAdapter(options: CodeAdapterOptions): boolean;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=code-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/code-adapter.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EACL,KAAK,wBAAwB,EAC7B,KAAK,aAAa,EAInB,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,sBAAsB,EACvB,oBAAiB;AAKlB,KAAK,SAAS,GAAG,wBAAwB,CAAC,MAAM,CAAC,GAAG;IAClD,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5B,CAAC;AAMF,UAAU,kBAAkB;IAC1B,iBAAiB,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,GAAG,SAAS,CAAC;IACtE,UAAU,CAAC,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,SAAS,CAAC;IACxD,oBAAoB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CACzD;AAwBD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,iFAexD,SAAS,qDA6Db;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAOzE"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { isValidElement, memo, } from "react";
|
|
4
|
+
import { useIsStreamdownCodeBlock } from "./PreOverride.js";
|
|
5
|
+
const LANGUAGE_REGEX = /language-([^\s]+)/;
|
|
6
|
+
/**
|
|
7
|
+
* Extracts code string from children.
|
|
8
|
+
*/
|
|
9
|
+
function extractCode(children) {
|
|
10
|
+
if (typeof children === "string")
|
|
11
|
+
return children;
|
|
12
|
+
if (!isValidElement(children))
|
|
13
|
+
return "";
|
|
14
|
+
const props = children.props;
|
|
15
|
+
if (props && typeof props["children"] === "string") {
|
|
16
|
+
return props["children"];
|
|
17
|
+
}
|
|
18
|
+
return "";
|
|
19
|
+
}
|
|
20
|
+
function DefaultPre({ node: _, ...props }) {
|
|
21
|
+
return _jsx("pre", { ...props });
|
|
22
|
+
}
|
|
23
|
+
function DefaultCode({ node: _, ...props }) {
|
|
24
|
+
return _jsx("code", { ...props });
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Creates a code component adapter that bridges the assistant-ui
|
|
28
|
+
* SyntaxHighlighter/CodeHeader API to streamdown's code component.
|
|
29
|
+
*/
|
|
30
|
+
export function createCodeAdapter(options) {
|
|
31
|
+
const { SyntaxHighlighter: UserSyntaxHighlighter, CodeHeader: UserCodeHeader, componentsByLanguage = {}, } = options;
|
|
32
|
+
/**
|
|
33
|
+
* Inner component that uses the hook for inline/block detection.
|
|
34
|
+
*/
|
|
35
|
+
function AdaptedCodeInner({ node, className, children, ...props }) {
|
|
36
|
+
// Use context-based detection for inline vs block code
|
|
37
|
+
const isCodeBlock = useIsStreamdownCodeBlock();
|
|
38
|
+
if (!isCodeBlock) {
|
|
39
|
+
// Inline code - render as simple code element
|
|
40
|
+
return (_jsx("code", { className: `aui-streamdown-inline-code ${className ?? ""}`.trim(), ...props, children: children }));
|
|
41
|
+
}
|
|
42
|
+
// Block code - extract language and code content
|
|
43
|
+
const match = className?.match(LANGUAGE_REGEX);
|
|
44
|
+
const language = match?.[1] ?? "";
|
|
45
|
+
const code = extractCode(children);
|
|
46
|
+
// Get language-specific or fallback components
|
|
47
|
+
const SyntaxHighlighter = componentsByLanguage[language]?.SyntaxHighlighter ??
|
|
48
|
+
UserSyntaxHighlighter;
|
|
49
|
+
const CodeHeader = componentsByLanguage[language]?.CodeHeader ?? UserCodeHeader;
|
|
50
|
+
// If user provided custom SyntaxHighlighter, use it
|
|
51
|
+
if (SyntaxHighlighter) {
|
|
52
|
+
return (_jsxs(_Fragment, { children: [CodeHeader && (_jsx(CodeHeader, { node: node, language: language, code: code })), _jsx(SyntaxHighlighter, { node: node, components: { Pre: DefaultPre, Code: DefaultCode }, language: language, code: code })] }));
|
|
53
|
+
}
|
|
54
|
+
// No custom SyntaxHighlighter - return null to let streamdown handle it
|
|
55
|
+
// This signals to the adapter that we should use streamdown's default
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const AdaptedCode = memo(AdaptedCodeInner, (prev, next) => {
|
|
59
|
+
return (prev.className === next.className &&
|
|
60
|
+
prev.children === next.children &&
|
|
61
|
+
prev.node?.position?.start.line === next.node?.position?.start.line &&
|
|
62
|
+
prev.node?.position?.end.line === next.node?.position?.end.line);
|
|
63
|
+
});
|
|
64
|
+
return AdaptedCode;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Checks if the code adapter should be used (i.e., user provided custom components).
|
|
68
|
+
*/
|
|
69
|
+
export function shouldUseCodeAdapter(options) {
|
|
70
|
+
return !!(options.SyntaxHighlighter ||
|
|
71
|
+
options.CodeHeader ||
|
|
72
|
+
(options.componentsByLanguage &&
|
|
73
|
+
Object.keys(options.componentsByLanguage).length > 0));
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=code-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-adapter.js","sourceRoot":"","sources":["../../src/adapters/code-adapter.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAGb,OAAO,EAGL,cAAc,EACd,IAAI,GAEL,MAAM,OAAO,CAAC;AAMf,OAAO,EAAE,wBAAwB,EAAE,yBAAsB;AAEzD,MAAM,cAAc,GAAG,mBAAmB,CAAC;AAgB3C;;GAEG;AACH,SAAS,WAAW,CAAC,QAAiB;IACpC,IAAI,OAAO,QAAQ,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAClD,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAEzC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAuC,CAAC;IAC/D,IAAI,KAAK,IAAI,OAAO,KAAK,CAAC,UAAU,CAAC,KAAK,QAAQ,EAAE,CAAC;QACnD,OAAO,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,UAAU,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAY;IACjD,OAAO,iBAAS,KAAK,GAAI,CAAC;AAC5B,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,KAAK,EAAa;IACnD,OAAO,kBAAU,KAAK,GAAI,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAA2B;IAC3D,MAAM,EACJ,iBAAiB,EAAE,qBAAqB,EACxC,UAAU,EAAE,cAAc,EAC1B,oBAAoB,GAAG,EAAE,GAC1B,GAAG,OAAO,CAAC;IAEZ;;OAEG;IACH,SAAS,gBAAgB,CAAC,EACxB,IAAI,EACJ,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACE;QACV,uDAAuD;QACvD,MAAM,WAAW,GAAG,wBAAwB,EAAE,CAAC;QAE/C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,8CAA8C;YAC9C,OAAO,CACL,eACE,SAAS,EAAE,8BAA8B,SAAS,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,KAC7D,KAAK,YAER,QAAQ,GACJ,CACR,CAAC;QACJ,CAAC;QAED,iDAAiD;QACjD,MAAM,KAAK,GAAG,SAAS,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;QAEnC,+CAA+C;QAC/C,MAAM,iBAAiB,GACrB,oBAAoB,CAAC,QAAQ,CAAC,EAAE,iBAAiB;YACjD,qBAAqB,CAAC;QAExB,MAAM,UAAU,GACd,oBAAoB,CAAC,QAAQ,CAAC,EAAE,UAAU,IAAI,cAAc,CAAC;QAE/D,oDAAoD;QACpD,IAAI,iBAAiB,EAAE,CAAC;YACtB,OAAO,CACL,8BACG,UAAU,IAAI,CACb,KAAC,UAAU,IAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,GAAI,CAC3D,EACD,KAAC,iBAAiB,IAChB,IAAI,EAAE,IAAI,EACV,UAAU,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,WAAW,EAAE,EAClD,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,GACV,IACD,CACJ,CAAC;QACJ,CAAC;QAED,wEAAwE;QACxE,sEAAsE;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACxD,OAAO,CACL,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS;YACjC,IAAI,CAAC,QAAQ,KAAK,IAAI,CAAC,QAAQ;YAC/B,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI;YACnE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,CAChE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAA2B;IAC9D,OAAO,CAAC,CAAC,CACP,OAAO,CAAC,iBAAiB;QACzB,OAAO,CAAC,UAAU;QAClB,CAAC,OAAO,CAAC,oBAAoB;YAC3B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CACxD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StreamdownProps } from "streamdown";
|
|
2
|
+
import type { ComponentsByLanguage, StreamdownTextComponents } from "../types.js";
|
|
3
|
+
interface UseAdaptedComponentsOptions {
|
|
4
|
+
components?: StreamdownTextComponents | undefined;
|
|
5
|
+
componentsByLanguage?: ComponentsByLanguage | undefined;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Hook that adapts assistant-ui component API to streamdown's component API.
|
|
9
|
+
*
|
|
10
|
+
* Handles:
|
|
11
|
+
* - SyntaxHighlighter -> custom code component
|
|
12
|
+
* - CodeHeader -> custom code component
|
|
13
|
+
* - componentsByLanguage -> custom code component with language dispatch
|
|
14
|
+
* - PreOverride -> context-based inline/block code detection
|
|
15
|
+
*/
|
|
16
|
+
export declare function useAdaptedComponents({ components, componentsByLanguage, }: UseAdaptedComponentsOptions): StreamdownProps["components"];
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=components-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/components-adapter.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAGlD,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,oBAAiB;AAE/E,UAAU,2BAA2B;IACnC,UAAU,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAClD,oBAAoB,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CACzD;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,UAAU,EACV,oBAAoB,GACrB,EAAE,2BAA2B,GAAG,eAAe,CAAC,YAAY,CAAC,CAyB7D"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { createCodeAdapter, shouldUseCodeAdapter } from "./code-adapter.js";
|
|
4
|
+
import { PreOverride } from "./PreOverride.js";
|
|
5
|
+
/**
|
|
6
|
+
* Hook that adapts assistant-ui component API to streamdown's component API.
|
|
7
|
+
*
|
|
8
|
+
* Handles:
|
|
9
|
+
* - SyntaxHighlighter -> custom code component
|
|
10
|
+
* - CodeHeader -> custom code component
|
|
11
|
+
* - componentsByLanguage -> custom code component with language dispatch
|
|
12
|
+
* - PreOverride -> context-based inline/block code detection
|
|
13
|
+
*/
|
|
14
|
+
export function useAdaptedComponents({ components, componentsByLanguage, }) {
|
|
15
|
+
return useMemo(() => {
|
|
16
|
+
const { SyntaxHighlighter, CodeHeader, ...htmlComponents } = components ?? {};
|
|
17
|
+
const codeAdapterOptions = {
|
|
18
|
+
SyntaxHighlighter,
|
|
19
|
+
CodeHeader,
|
|
20
|
+
componentsByLanguage,
|
|
21
|
+
};
|
|
22
|
+
const baseComponents = { pre: PreOverride };
|
|
23
|
+
if (!shouldUseCodeAdapter(codeAdapterOptions)) {
|
|
24
|
+
return { ...htmlComponents, ...baseComponents };
|
|
25
|
+
}
|
|
26
|
+
const AdaptedCode = createCodeAdapter(codeAdapterOptions);
|
|
27
|
+
return {
|
|
28
|
+
...htmlComponents,
|
|
29
|
+
...baseComponents,
|
|
30
|
+
code: (props) => AdaptedCode(props) ?? undefined,
|
|
31
|
+
};
|
|
32
|
+
}, [components, componentsByLanguage]);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=components-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components-adapter.js","sourceRoot":"","sources":["../../src/adapters/components-adapter.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEhC,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,0BAAuB;AACzE,OAAO,EAAE,WAAW,EAAE,yBAAsB;AAQ5C;;;;;;;;GAQG;AACH,MAAM,UAAU,oBAAoB,CAAC,EACnC,UAAU,EACV,oBAAoB,GACQ;IAC5B,OAAO,OAAO,CAAC,GAAG,EAAE;QAClB,MAAM,EAAE,iBAAiB,EAAE,UAAU,EAAE,GAAG,cAAc,EAAE,GACxD,UAAU,IAAI,EAAE,CAAC;QAEnB,MAAM,kBAAkB,GAAG;YACzB,iBAAiB;YACjB,UAAU;YACV,oBAAoB;SACrB,CAAC;QAEF,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC;QAE5C,IAAI,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC9C,OAAO,EAAE,GAAG,cAAc,EAAE,GAAG,cAAc,EAAE,CAAC;QAClD,CAAC;QAED,MAAM,WAAW,GAAG,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;QAE1D,OAAO;YACL,GAAG,cAAc;YACjB,GAAG,cAAc;YACjB,IAAI,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,SAAS;SACjD,CAAC;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,oBAAoB,CAAC,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { BundledTheme } from "streamdown";
|
|
2
|
+
import type { PluginConfig, ResolvedPluginConfig } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Default Shiki theme for code highlighting.
|
|
5
|
+
* First value is light theme, second is dark theme.
|
|
6
|
+
*/
|
|
7
|
+
export declare const DEFAULT_SHIKI_THEME: [BundledTheme, BundledTheme];
|
|
8
|
+
/**
|
|
9
|
+
* Merges user plugin configuration with detected defaults.
|
|
10
|
+
*
|
|
11
|
+
* Rules:
|
|
12
|
+
* - `false` = explicitly disable a plugin
|
|
13
|
+
* - `undefined` = use default (auto-detect)
|
|
14
|
+
* - plugin instance = use provided plugin
|
|
15
|
+
* - mermaid requires explicit enabling (not auto-detected)
|
|
16
|
+
*/
|
|
17
|
+
export declare function mergePlugins(userPlugins: PluginConfig | undefined, defaultPlugins: ResolvedPluginConfig): ResolvedPluginConfig;
|
|
18
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,oBAAoB,EAAE,mBAAgB;AAElE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,CAAC,YAAY,EAAE,YAAY,CAG5D,CAAC;AAIF;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,YAAY,GAAG,SAAS,EACrC,cAAc,EAAE,oBAAoB,GACnC,oBAAoB,CAiBtB"}
|
package/dist/defaults.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
/**
|
|
3
|
+
* Default Shiki theme for code highlighting.
|
|
4
|
+
* First value is light theme, second is dark theme.
|
|
5
|
+
*/
|
|
6
|
+
export const DEFAULT_SHIKI_THEME = [
|
|
7
|
+
"github-light",
|
|
8
|
+
"github-dark",
|
|
9
|
+
];
|
|
10
|
+
const PLUGIN_KEYS = ["code", "math", "cjk"];
|
|
11
|
+
/**
|
|
12
|
+
* Merges user plugin configuration with detected defaults.
|
|
13
|
+
*
|
|
14
|
+
* Rules:
|
|
15
|
+
* - `false` = explicitly disable a plugin
|
|
16
|
+
* - `undefined` = use default (auto-detect)
|
|
17
|
+
* - plugin instance = use provided plugin
|
|
18
|
+
* - mermaid requires explicit enabling (not auto-detected)
|
|
19
|
+
*/
|
|
20
|
+
export function mergePlugins(userPlugins, defaultPlugins) {
|
|
21
|
+
const result = {};
|
|
22
|
+
for (const key of PLUGIN_KEYS) {
|
|
23
|
+
const userValue = userPlugins?.[key];
|
|
24
|
+
if (userValue === false)
|
|
25
|
+
continue;
|
|
26
|
+
const value = userValue || defaultPlugins[key];
|
|
27
|
+
if (value)
|
|
28
|
+
result[key] = value;
|
|
29
|
+
}
|
|
30
|
+
// Mermaid requires explicit enabling (not auto-detected)
|
|
31
|
+
const mermaid = userPlugins?.mermaid;
|
|
32
|
+
if (mermaid && mermaid !== false) {
|
|
33
|
+
result["mermaid"] = mermaid;
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAKb;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAiC;IAC/D,cAAc;IACd,aAAa;CACd,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAU,CAAC;AAErD;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAC1B,WAAqC,EACrC,cAAoC;IAEpC,MAAM,MAAM,GAA4B,EAAE,CAAC;IAE3C,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,SAAS,KAAK,KAAK;YAAE,SAAS;QAClC,MAAM,KAAK,GAAG,SAAS,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC;QAC/C,IAAI,KAAK;YAAE,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACjC,CAAC;IAED,yDAAyD;IACzD,MAAM,OAAO,GAAG,WAAW,EAAE,OAAO,CAAC;IACrC,IAAI,OAAO,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;QACjC,MAAM,CAAC,SAAS,CAAC,GAAG,OAAO,CAAC;IAC9B,CAAC;IAED,OAAO,MAA8B,CAAC;AACxC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { StreamdownTextPrimitive } from "./primitives/StreamdownText.js";
|
|
2
|
+
export { useIsStreamdownCodeBlock, useStreamdownPreProps, } from "./adapters/PreOverride.js";
|
|
3
|
+
export { DEFAULT_SHIKI_THEME } from "./defaults.js";
|
|
4
|
+
export { memoCompareNodes } from "./memoization.js";
|
|
5
|
+
export type { StreamdownTextPrimitiveProps, SyntaxHighlighterProps, CodeHeaderProps, ComponentsByLanguage, StreamdownTextComponents, PluginConfig, ResolvedPluginConfig, CaretStyle, ControlsConfig, LinkSafetyConfig, LinkSafetyModalProps, RemendConfig, RemendHandler, MermaidOptions, MermaidErrorComponentProps, AllowedTags, RemarkRehypeOptions, BlockProps, SecurityConfig, } from "./types.js";
|
|
6
|
+
export { StreamdownContext, parseMarkdownIntoBlocks } from "streamdown";
|
|
7
|
+
export type { StreamdownProps, CodeHighlighterPlugin, DiagramPlugin, MathPlugin, CjkPlugin, HighlightOptions, } from "streamdown";
|
|
8
|
+
export type { BundledTheme, BundledLanguage } from "streamdown";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,uCAAoC;AACtE,OAAO,EACL,wBAAwB,EACxB,qBAAqB,GACtB,kCAA+B;AAChC,OAAO,EAAE,mBAAmB,EAAE,sBAAmB;AACjD,OAAO,EAAE,gBAAgB,EAAE,yBAAsB;AAEjD,YAAY,EACV,4BAA4B,EAC5B,sBAAsB,EACtB,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,YAAY,EACZ,oBAAoB,EACpB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,0BAA0B,EAC1B,WAAW,EACX,mBAAmB,EACnB,UAAU,EACV,cAAc,GACf,mBAAgB;AAGjB,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAGxE,YAAY,EACV,eAAe,EACf,qBAAqB,EACrB,aAAa,EACb,UAAU,EACV,SAAS,EACT,gBAAgB,GACjB,MAAM,YAAY,CAAC;AAGpB,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { StreamdownTextPrimitive } from "./primitives/StreamdownText.js";
|
|
2
|
+
export { useIsStreamdownCodeBlock, useStreamdownPreProps, } from "./adapters/PreOverride.js";
|
|
3
|
+
export { DEFAULT_SHIKI_THEME } from "./defaults.js";
|
|
4
|
+
export { memoCompareNodes } from "./memoization.js";
|
|
5
|
+
// Re-export streamdown context and utilities
|
|
6
|
+
export { StreamdownContext, parseMarkdownIntoBlocks } from "streamdown";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,uCAAoC;AACtE,OAAO,EACL,wBAAwB,EACxB,qBAAqB,GACtB,kCAA+B;AAChC,OAAO,EAAE,mBAAmB,EAAE,sBAAmB;AACjD,OAAO,EAAE,gBAAgB,EAAE,yBAAsB;AAwBjD,6CAA6C;AAC7C,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Memo comparison function for components with children prop.
|
|
4
|
+
* Inspired by react-markdown's approach.
|
|
5
|
+
*/
|
|
6
|
+
export declare function memoCompareNodes<T extends {
|
|
7
|
+
children?: ReactNode;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}>(prev: Readonly<T>, next: Readonly<T>): boolean;
|
|
10
|
+
//# sourceMappingURL=memoization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoization.d.ts","sourceRoot":"","sources":["../src/memoization.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAmBvC;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,SAAS;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CAAE,EAC1D,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,OAAO,CAU/C"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
function isReactElement(node) {
|
|
3
|
+
return (typeof node === "object" && node !== null && "type" in node && "key" in node);
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Compares two ReactNode values for shallow equality.
|
|
7
|
+
*/
|
|
8
|
+
function compareNodes(a, b) {
|
|
9
|
+
if (a === b)
|
|
10
|
+
return true;
|
|
11
|
+
if (!isReactElement(a) || !isReactElement(b))
|
|
12
|
+
return false;
|
|
13
|
+
return a.type === b.type && a.key === b.key;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Memo comparison function for components with children prop.
|
|
17
|
+
* Inspired by react-markdown's approach.
|
|
18
|
+
*/
|
|
19
|
+
export function memoCompareNodes(prev, next) {
|
|
20
|
+
const prevKeys = Object.keys(prev).filter((k) => k !== "children");
|
|
21
|
+
const nextKeys = Object.keys(next).filter((k) => k !== "children");
|
|
22
|
+
if (prevKeys.length !== nextKeys.length)
|
|
23
|
+
return false;
|
|
24
|
+
for (const key of prevKeys) {
|
|
25
|
+
if (prev[key] !== next[key])
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return compareNodes(prev.children, next.children);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=memoization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memoization.js","sourceRoot":"","sources":["../src/memoization.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAMb,SAAS,cAAc,CAAC,IAAa;IACnC,OAAO,CACL,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,CAC7E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,CAAY,EAAE,CAAY;IAC9C,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3D,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAE9B,IAAiB,EAAE,IAAiB;IACpC,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC;IACnE,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC;IAEnE,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACtD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;IAC5C,CAAC;IAED,OAAO,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type StreamdownProps } from "streamdown";
|
|
2
|
+
import type { SecurityConfig } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* A primitive component for rendering markdown text using Streamdown.
|
|
5
|
+
*
|
|
6
|
+
* Streamdown is optimized for AI-powered streaming with features like:
|
|
7
|
+
* - Block-based rendering for better streaming performance
|
|
8
|
+
* - Incomplete markdown handling via remend
|
|
9
|
+
* - Built-in syntax highlighting via Shiki
|
|
10
|
+
* - Math, Mermaid, and CJK support via plugins
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* // Basic usage
|
|
15
|
+
* <StreamdownTextPrimitive />
|
|
16
|
+
*
|
|
17
|
+
* // With plugins
|
|
18
|
+
* import { code } from "@streamdown/code";
|
|
19
|
+
* import { math } from "@streamdown/math";
|
|
20
|
+
*
|
|
21
|
+
* <StreamdownTextPrimitive
|
|
22
|
+
* plugins={{ code, math }}
|
|
23
|
+
* shikiTheme={["github-light", "github-dark"]}
|
|
24
|
+
* />
|
|
25
|
+
*
|
|
26
|
+
* // Disable a specific plugin
|
|
27
|
+
* <StreamdownTextPrimitive plugins={{ code: false }} />
|
|
28
|
+
*
|
|
29
|
+
* // Migration from react-markdown (compatibility mode)
|
|
30
|
+
* <StreamdownTextPrimitive
|
|
31
|
+
* components={{
|
|
32
|
+
* SyntaxHighlighter: MySyntaxHighlighter,
|
|
33
|
+
* CodeHeader: MyCodeHeader,
|
|
34
|
+
* }}
|
|
35
|
+
* componentsByLanguage={{
|
|
36
|
+
* mermaid: { SyntaxHighlighter: MermaidRenderer }
|
|
37
|
+
* }}
|
|
38
|
+
* />
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare const StreamdownTextPrimitive: import("react").ForwardRefExoticComponent<Omit<StreamdownProps, "children" | "components" | "plugins" | "caret" | "controls" | "linkSafety" | "remend" | "mermaid" | "BlockComponent" | "parseMarkdownIntoBlocksFn"> & {
|
|
42
|
+
components?: import("..").StreamdownTextComponents | undefined;
|
|
43
|
+
componentsByLanguage?: import("..").ComponentsByLanguage | undefined;
|
|
44
|
+
plugins?: import("..").PluginConfig | undefined;
|
|
45
|
+
preprocess?: ((text: string) => string) | undefined;
|
|
46
|
+
containerProps?: Omit<import("react").ComponentPropsWithoutRef<"div">, "children"> | undefined;
|
|
47
|
+
containerClassName?: string | undefined;
|
|
48
|
+
caret?: import("..").CaretStyle | undefined;
|
|
49
|
+
controls?: import("..").ControlsConfig | undefined;
|
|
50
|
+
linkSafety?: import("..").LinkSafetyConfig | undefined;
|
|
51
|
+
remend?: import("..").RemendConfig | undefined;
|
|
52
|
+
mermaid?: import("streamdown").MermaidOptions | undefined;
|
|
53
|
+
parseIncompleteMarkdown?: boolean | undefined;
|
|
54
|
+
allowedTags?: import("..").AllowedTags | undefined;
|
|
55
|
+
remarkRehypeOptions?: import("remark-rehype").Options | undefined;
|
|
56
|
+
security?: SecurityConfig | undefined;
|
|
57
|
+
BlockComponent?: StreamdownProps["BlockComponent"] | undefined;
|
|
58
|
+
parseMarkdownIntoBlocksFn?: ((markdown: string) => string[]) | undefined;
|
|
59
|
+
} & import("react").RefAttributes<HTMLDivElement>>;
|
|
60
|
+
//# sourceMappingURL=StreamdownText.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamdownText.d.ts","sourceRoot":"","sources":["../../src/primitives/StreamdownText.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAI9D,OAAO,KAAK,EAAE,cAAc,EAAgC,oBAAiB;AA8B7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,uBAAuB;;;;;;;;;;;;;;;;;;kDAwHnC,CAAC"}
|