用于渲染交互式 MarkdownFlow 文档的 React 组件库,具有打字机效果和实时流式传输功能。
MarkdownFlow(也称为 MDFlow 或 markdown-flow)通过 AI 扩展了标准 Markdown,用于创建个性化的交互式页面。我们的口号是:“一次创作,千人千面”。
English | 简体中文
npm install markdown-flow-ui
# 或
yarn add markdown-flow-ui
# 或
pnpm add markdown-flow-ui
import { MarkdownFlow } from "markdown-flow-ui";
function App() {
return (
<MarkdownFlow
initialContentList={[
{ content: "# Hello World\n\n这是带有打字机效果的 **MarkdownFlow**!" },
]}
disableTyping={false}
typingSpeed={30}
/>
);
}
import { MarkdownFlow } from "markdown-flow-ui";
function InteractiveExample() {
const content = `
选择您的语言:?[%{{lang}} English | 中文 | Español]
您的姓名:?[%{{name}} 输入您的姓名...]
?[继续 | 取消]
`;
return (
<MarkdownFlow
initialContentList={[{ content }]}
onSend={(params) => {
console.log("用户交互:", params);
// 处理按钮点击和输入提交
}}
/>
);
}
import { ScrollableMarkdownFlow } from "markdown-flow-ui";
import { useSSE } from "markdown-flow-ui";
function StreamingChat() {
const [messages, setMessages] = useState([]);
const { data, isConnected } = useSSE("/api/stream", {
onMessage: (chunk) => {
setMessages((prev) => {
const last = prev[prev.length - 1];
if (last && !last.isFinished) {
return [
...prev.slice(0, -1),
{ ...last, content: last.content + chunk },
];
}
return [...prev, { content: chunk, isFinished: false }];
});
},
});
return (
<ScrollableMarkdownFlow
height="500px"
initialContentList={messages}
onSend={(params) => {
// 发送用户输入到后端
fetch("/api/chat", {
method: "POST",
body: JSON.stringify(params),
});
}}
/>
);
}
用于渲染带有打字机效果的 markdown 的主要组件。
interface MarkdownFlowProps {
initialContentList?: ContentItem[];
customRenderBar?: CustomRenderBarProps;
onSend?: (content: OnSendContentParams) => void;
typingSpeed?: number;
disableTyping?: boolean;
onBlockComplete?: (blockIndex: number) => void;
}
type ContentItem = {
content: string;
isFinished?: boolean;
defaultInputText?: string;
defaultButtonText?: string;
readonly?: boolean;
customRenderBar?: CustomRenderBarProps;
};
type OnSendContentParams = {
buttonText?: string;
variableName?: string;
inputText?: string;
};
属性:
initialContentList - 要渲染的内容块数组typingSpeed - 打字动画速度(默认:30ms/字符)disableTyping - 禁用打字机效果(默认:false)onSend - 用户交互的回调onBlockComplete - 当块完成打字时调用customRenderBar - 用于附加 UI 的自定义组件示例:
<MarkdownFlow
initialContentList={[
{
content: "# 欢迎\n\n选择:?[%{{choice}} A | B | C]",
isFinished: false,
},
]}
typingSpeed={50}
onSend={(params) => {
if (params.variableName === "choice") {
console.log("已选择:", params.buttonText);
}
}}
/>
具有自动滚动和滚动管理的增强版本。
interface ScrollableMarkdownFlowProps extends MarkdownFlowProps {
height?: string | number;
className?: string;
}
附加属性:
height - 容器高度(默认:"100%")className - 附加 CSS 类功能:
示例:
<ScrollableMarkdownFlow
height="400px"
initialContentList={messages}
onSend={handleUserMessage}
className="chat-container"
/>
用于渲染单个 markdown 块的核心组件。
interface ContentRenderProps {
content: string;
customRenderBar?: CustomRenderBarProps;
onSend?: (content: OnSendContentParams) => void;
typingSpeed?: number;
disableTyping?: boolean;
defaultButtonText?: string;
defaultInputText?: string;
readonly?: boolean;
onTypeFinished?: () => void;
tooltipMinLength?: number;
}
属性:
content - 要渲染的 Markdown 内容typingSpeed - 动画速度(默认:30)disableTyping - 禁用动画(默认:true)readonly - 使交互元素只读onTypeFinished - 打字完成时调用tooltipMinLength - 工具提示的最小长度(默认:10)支持的 Markdown:
$E = mc^2$自定义语法:
# 按钮
?[点击我]
# 变量输入
?[%{{userName}} 输入姓名...]
# 多选
?[%{{color}} 红色 | 蓝色 | 绿色]
# Mermaid 图表
```mermaid
graph LR
A --> B
B --> C
```
管理打字机动画效果。
function useTypewriter(
content: string,
speed?: number,
disabled?: boolean
): {
displayText: string;
isComplete: boolean;
start: () => void;
pause: () => void;
reset: () => void;
};
示例:
const { displayText, isComplete, start, pause } = useTypewriter(
"Hello, World!",
50,
false
);
return (
<div>
<p>{displayText}</p>
{!isComplete && <button onClick={pause}>暂停</button>}
</div>
);
容器的自动滚动管理。
function useScrollToBottom(
containerRef: RefObject<HTMLElement>,
dependencies: any[],
options?: {
behavior?: "smooth" | "auto";
autoScrollOnInit?: boolean;
scrollDelay?: number;
}
): {
showScrollToBottom: boolean;
handleUserScrollToBottom: () => void;
};
示例:
const containerRef = useRef(null);
const { showScrollToBottom, handleUserScrollToBottom } = useScrollToBottom(
containerRef,
[messages.length],
{ behavior: "smooth" }
);
return (
<div ref={containerRef}>
{messages.map((msg) => (
<div key={msg.id}>{msg.text}</div>
))}
{showScrollToBottom && (
<button onClick={handleUserScrollToBottom}>↓</button>
)}
</div>
);
服务器发送事件集成。
function useSSE(
url: string,
options?: {
onMessage?: (data: any) => void;
onError?: (error: Error) => void;
onOpen?: () => void;
reconnect?: boolean;
reconnectInterval?: number;
}
): {
data: any;
isConnected: boolean;
error: Error | null;
close: () => void;
};
示例:
const { data, isConnected, error } = useSSE("/api/stream", {
onMessage: (chunk) => {
setContent((prev) => prev + chunk);
},
reconnect: true,
reconnectInterval: 3000,
});
// 流中的内容项
type ContentItem = {
content: string;
isFinished?: boolean;
defaultInputText?: string;
defaultButtonText?: string;
readonly?: boolean;
customRenderBar?: CustomRenderBarProps;
};
// 用户交互参数
type OnSendContentParams = {
buttonText?: string;
variableName?: string;
inputText?: string;
};
// 自定义渲染栏组件
type CustomRenderBarProps = React.ComponentType<{
content?: string;
onSend?: (content: OnSendContentParams) => void;
displayContent: string;
}>;
// 所有组件属性都已导出
import type {
MarkdownFlowProps,
ScrollableMarkdownFlowProps,
ContentRenderProps,
} from "markdown-flow-ui";
自定义变量插件:
处理交互式按钮和输入。
?[按钮文本] # 简单按钮 ?[%{{variable}} 占位符...] # 输入字段 ?[%{{choice}} A | B | C] # 多选
Mermaid 插件:
使用 Mermaid 渲染图表。
```mermaid
graph TD
A[开始] --> B[处理]
B --> C[结束]
```
// 定义插件组件
const CustomPlugin: React.FC<{ value: string; type?: string }> = ({
value,
type = 'default'
}) => {
return (
<div className="custom-plugin">
<span>{type}: {value}</span>
</div>
);
};
// 注册到 ContentRender
const components = {
'custom-element': CustomPlugin,
};
该库使用 Tailwind CSS 并通过以下方式提供自定义:
CSS 类:
.markdown-flow {
}
.content-render {
}
.content-render-table {
}
.content-render-ol {
}
.content-render-ul {
}
.scrollable-markdown-container {
}
.scroll-to-bottom-btn {
}
CSS 变量:
:root {
--markdown-flow-primary: #2563eb;
--markdown-flow-background: #ffffff;
--markdown-flow-text: #1f2937;
--markdown-flow-border: #d1d5db;
--markdown-flow-code-bg: #f3f4f6;
}
组件类:
<MarkdownFlow className="my-custom-flow" />
<ScrollableMarkdownFlow className="chat-interface" />
const CustomBar: CustomRenderBarProps = ({ displayContent, onSend }) => {
return (
<div className="flex gap-2 mt-4">
<button
onClick={() => onSend({ buttonText: "重新生成" })}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
重新生成
</button>
<button
onClick={() => navigator.clipboard.writeText(displayContent)}
className="px-4 py-2 bg-gray-500 text-white rounded"
>
复制
</button>
</div>
);
};
<MarkdownFlow customRenderBar={CustomBar} initialContentList={messages} />;
const StreamingChat = () => {
const [content, setContent] = useState("");
useSSE("/api/stream", {
onMessage: (data) => {
setContent((prev) => prev + data.chunk);
},
});
return (
<ScrollableMarkdownFlow
initialContentList={[{ content, isFinished: false }]}
disableTyping={false}
typingSpeed={20}
/>
);
};
const Conversation = () => {
const [blocks, setBlocks] = useState([
{ content: "# 助手\n\n你好!我能帮你什么?", isFinished: true },
{
content: "你想了解什么?\n\n?[%{{topic}} 输入主题...]",
isFinished: false,
},
]);
const handleSend = (params) => {
if (params.variableName === "topic") {
setBlocks((prev) => [
...prev,
{ content: `你询问了:${params.inputText}`, isFinished: false },
]);
}
};
return (
<MarkdownFlow
initialContentList={blocks}
onSend={handleSend}
onBlockComplete={(index) => {
setBlocks((prev) =>
prev.map((b, i) => (i === index ? { ...b, isFinished: true } : b))
);
}}
/>
);
};
markdown-flow-ui 是 MarkdownFlow 生态系统的一部分,用于创建个性化、AI 驱动的交互式文档:
MIT 许可证 - 详见 LICENSE 文件。