@roaming-ai/react-streaming
v0.2.0
Published
React components, hooks, and pluggable effects for sequential streaming UI.
Readme
@roaming-ai/react-streaming
React components and hooks for sequential streaming effects.
Install
npm install @roaming-ai/react-streamingReact is a peer dependency and is not bundled.
Usage
Each item supplies a stable key and a React node. Streaming shows items in
order, while an effect controls how each item is revealed.
import React from 'react';
import { Streaming, TypewriterEffect } from '@roaming-ai/react-streaming';
import type { StreamingItem } from '@roaming-ai/react-streaming';
const items: StreamingItem[] = [
{
key: 'summary',
content: (
<section>
<h2>Summary</h2>
<p>The summary is typed out first.</p>
</section>
)
},
{
key: 'analysis',
content: (
<section>
<h2>Analysis</h2>
<p>The analysis follows after the summary.</p>
</section>
)
}
];
export const Report = ({ streaming }: { streaming: boolean }) => (
<Streaming
items={items}
enabled={streaming}
effect={TypewriterEffect}
effectOptions={{ speed: 30 }}
fallback={<div>Loading next section...</div>}
/>
);Effects
Effects are React components that receive content, onFinish, animation,
and optional options.
Built-in effects:
TypewriterEffect: reveals text character by character.WordRevealEffect: reveals text word by word.BlockRevealEffect: delays and fades in the whole content block.ListRevealEffect: fades in the direct children of the content root in order.
const FadeEffect: React.FC<StreamingEffectProps> = ({
content,
onFinish
}) => {
React.useEffect(() => {
const timer = window.setTimeout(onFinish, 300);
return () => window.clearTimeout(timer);
}, [onFinish]);
return <>{content}</>;
};Pass an effect to Streaming for the default, or set effect on one item to
override it. Use effect={null} to complete an item immediately.
Markdown
MarkdownStream heals incomplete syntax with remend, splits into blocks, and
memoizes completed blocks. Pass render for actual Markdown-to-React mapping.
Put it in one StreamingItem with effect={null}. Do not wrap it in
TypewriterEffect.
import ReactMarkdown from 'react-markdown';
import { MarkdownStream, Streaming } from '@roaming-ai/react-streaming';
<Streaming
items={[
{
key: 'markdown',
content: (
<MarkdownStream
markdown={text}
render={(block) => <ReactMarkdown>{block}</ReactMarkdown>}
/>
),
effect: null
}
]}
enabled={streaming}
/>useStreamingAutoScroll can keep a scroll container pinned to the latest
streamed content:
const { containerRef, bottomRef } = useStreamingAutoScroll({
enabled: streaming,
deps: [visibleItems.length],
behavior: 'smooth'
});Storybook
Run the interactive component demos locally:
npm run storybookBuild the static Storybook site:
npm run storybook:buildThe Components/Streaming dashboard story demonstrates a longer mixed
sequence with prose, metric cards, a local image, chart-like UI, a table, a
quote, and action cards.
