StreamElement
An element that streams a whole AI answer.
Installation
pnpm add @talex-touch/tuffex
import { TxStreamElement } from '@talex-touch/tuffex/stream-element'
import '@talex-touch/tuffex/stream-element/style.css'
import '@talex-touch/tuffex/base.css' // once per app
Usage
AI Answer
[n] markers resolve against sources into citation chips; actions, sources, and follow-ups go in the footer slot and appear on done.
Loading demo...
Delegated Markdown
Delegated parts such as tables and math reveal line by line on the same clock as native parts; reserve keeps content below still during playback.
Loading demo...
Slots and State
parts takes structure directly; a part-<name> slot renders the custom part of that name.
Loading demo...
Best Practices
- Pass the whole answer so far, not the latest delta.
- Keep
streamingtrue until the source has really finished, so a half-written**boldor`codeat the end is closed and its markers never flash. - Put what belongs to a finished answer (actions, sources, follow-ups) in the
footerslot behinddone; the answer has no bottom margin, so space the footer yourself. - Copy and share the full answer you hold, never what is on screen.
- Use
TxStreamTextfor a single run of text andTxStreamMarkdownwhen you don't need the word-by-word reveal.
API Reference
Props
| Name | Type | Default | Description |
|---|---|---|---|
content | string | '' | All the Markdown received so far. |
parts | StreamPart[] | — | Structured alternative to content; wins when both are set. |
streaming | boolean | false | The source is still producing. |
sources | AiSourceItem[] | — | In the order the model cites them; [n] resolves to a chip for sources[n - 1]. |
wordMs | number | 24 | Releases one word every wordMs. |
maxLagMs | number | 600 | No word shows later than this after it arrives. |
drainMs | number | 320 | Once streaming turns false, releases the rest within this. |
pauseMs | number | 400 | Reports paused after this long without a new word. |
reveal | 'aurora' | 'hue' | 'blur' | 'languid' | 'none' | 'aurora' | How a word enters, with TxStreamText's presets; code keeps its syntax color. |
caret | boolean | true | Shows the caret at the write head while live. |
reserve | boolean | false | Holds the final layout during playback, plus the answer's current height from replay(); ignored while streaming. |
renderers | Record<string, Component> | — | Components for custom parts, by name; a part-<name> slot wins. |
markdownProps | Partial<StreamMarkdownProps> | — | Forwarded to the TxStreamMarkdown that renders delegated parts. |
locale | string | 'zh' | Locale for Intl.Segmenter word segmentation. |
Events
| Name | Payload | Description |
|---|---|---|
state-change | (state: StreamState) | Fires when the stream changes state. |
done | — | Fires once per play-through, when the last word shows and the source has finished. |
cite | (source: AiSourceItem) | Fires when a citation chip opens; the chip never navigates. |
Slots
| Name | Scope | Description |
|---|---|---|
caret | { state } | Replaces the caret at the write head of text and code. |
citation | { source, label, index } | Replaces a citation chip. |
inline | { name, props } | Renders a custom inline inside text. |
code | { part, code, streaming } | Replaces a code block; code is what has been revealed. |
part-<name> | { part, state } | Renders { type: 'custom', name } parts. |
footer | { state, done } | Below the answer; done once the last word shows and the source has finished. |
Exposed Methods
| Name | Type | Description |
|---|---|---|
state | StreamState | The current stream state. |
replay | () => void | Plays the whole answer again from the first word. |
skip | () => void | Shows everything now, without entrances. |
Types
type StreamPart =
| { type: 'heading', depth: 1 | 2 | 3 | 4 | 5 | 6, inlines: StreamInline[] }
| { type: 'paragraph', inlines: StreamInline[], tight?: boolean }
| { type: 'list', ordered: boolean, start?: number, items: { checked?: boolean, parts: StreamPart[] }[] }
| { type: 'quote', parts: StreamPart[] }
| { type: 'rule' }
| { type: 'code', lang?: string, code: string, filename?: string }
| { type: 'markdown', raw: string }
| { type: 'custom', name: string, props?: Record<string, unknown> }
CSS Variables
| Variable | Default | Description |
|---|---|---|
--tx-stream-reveal-1 / -2 / -3 | blue / violet / pink, per theme | The sweep's color stops, shared with TxStreamText. |
--tx-stream-reveal-duration | the preset's | Written onto the root from reveal; hosts do not set it. |
Overview
- Pacing, states, incremental reveal, and degradation match StreamText; all parts sit on one clock in document order.
- Rendered natively, word by word: headings, paragraphs, emphasis, strikethrough, inline code, safe links, lists (nested, task), quotes, rules, and fenced code (
TxCodeStream). - Tables, math, mermaid, raw HTML, and images are delegated whole to
TxStreamMarkdown, with its sanitizing and remote-image policy, and reveal line by line; neighboring delegated blocks form one part. - The caret sits only at the write head: one per answer at any time, retracting when the answer ends.
[n]becomes a citation chip (a link named after its source) only in plain text, never in code or link text; without a matching source it stays text.
Technologies
- Built on
TxStreamText,TxCodeStream, andTxStreamMarkdown:parse.tsturns Markdown into parts andplan.tslays them on the clock. - Source:
packages/tuffex/packages/components/src/stream-element/.
查看源码
packages/tuffex/packages/components/src/stream-element/index.ts
Use cases
- A chat reply or assistant panel answer, with sources, code, and follow-ups.
- A generated report that mixes prose, lists, tables, and formulas.
- Replaying a stored answer in a card or demo, with
reserve.
Related components
- StreamText streams one run of text; the element is built on it.
- CodeStream renders its code parts.
- StreamMarkdown renders its delegated parts.
- Sources, MessageActions, and SuggestionChips finish an answer in the
footerslot.