StreamText
Text that streams in word by word at a steady pace.
Installation
pnpm add @talex-touch/tuffex
import { TxStreamText } from '@talex-touch/tuffex/stream-text'
import '@talex-touch/tuffex/stream-text/style.css'
import '@talex-touch/tuffex/inline-citation/style.css' // citation chips
import '@talex-touch/tuffex/base.css' // once per app
Usage
Streaming
Pass everything received so far as content, and keep streaming on while the source is live.
Loading demo...
Reveal Presets
reveal sets how a word enters. With complete content, replay() plays it again and reserve keeps the layout still.
Loading demo...
Slots and State
content also takes a list of runs: text with marks and links, citations, and custom runs.
Loading demo...
Best Practices
- Pass the whole text so far, not the latest delta.
- Keep
streamingtrue until the source has really finished; leave it off for complete answers (history, replays) and usereplay()to play them. - Turn on
reservewhen complete text plays back in a layout that must not move, such as a card or a bubble. - Copy and share the full text you hold: the display trails the source by up to
maxLagMs. - The component is not a live region; wrap the conversation in
role="log"to announce replies.
API Reference
Props
| Name | Type | Default | Description |
|---|---|---|---|
content | string | StreamInline[] | — | Everything received so far. Required. |
streaming | boolean | false | The source is live; a possibly unfinished last word waits for what follows or 200ms of quiet. |
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; see StreamRevealPreset. |
caret | boolean | true | Shows the caret while live; switched off, it goes at once. |
reserve | boolean | false | Holds the final layout with an invisible copy during playback; ignored while streaming. |
paced | boolean | true | false shows each word as it arrives, still animated; TxStreamElement passes it to pace parts itself. |
appear | boolean | false | Content present at mount enters too. Read at mount. |
tag | string | 'span' | Root element. |
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 Tuff caret; rendered only while live. |
citation | { source, label, index } | Replaces the citation chip; index is the marker's number. |
inline | { name, props } | Renders { type: 'custom' } runs. |
Exposed Methods
| Name | Type | Description |
|---|---|---|
state | StreamState | The current stream state. |
replay | () => void | Plays the whole content again from the first word, at wordMs. |
skip | () => void | Shows everything now, without entrances. |
Types
type StreamState = 'idle' | 'streaming' | 'paused' | 'draining' | 'done'
type StreamRevealPreset =
| 'aurora' // fades out of a 4px blur through the blue–violet–pink sweep (default)
| 'hue' // the sweep alone
| 'blur' // the blur alone
| 'languid' // rises slowly out of an 8px blur
| 'none' // shows each word as it is released
type StreamInline =
| { type: 'text', text: string, marks?: ('strong' | 'em' | 'del' | 'code')[], href?: string }
| { type: 'citation', source: AiSourceItem, label?: string, index?: number }
| { 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; all equal the ink in high-contrast themes. |
--tx-stream-caret-start / --tx-stream-caret-end | #199ffe / #810dc6 | The caret gradient, from the Tuff logo. |
--tx-stream-reveal-duration | the preset's | Written onto the root from reveal; hosts do not set it. |
Overview
- Words go out every
wordMs; a burst speeds the release so each word shows withinmaxLagMsof arriving. Once the source stops, the rest drains withindrainMs. - States:
idle→streaming→paused(no new word forpauseMs) →draining(source finished, backlog still going out) →done; the caret retracts ondone. - Only new text enters: content present at mount shows at once, and a rewrite re-releases from the first changed word.
- Text splits by word with
Intl.Segmenter, punctuation staying with its word; without it, Latin splits on spaces and CJK by character. hrefrenders only forhttp(s),mailto,tel, relative, query, and hash URLs;//hoststays text. Links carryrel="noopener noreferrer".- Under reduced motion, nothing enters or is paced and the caret rests; server rendering outputs plain text; the root carries
aria-busy="true"while live. - The caret and the
reservecopy are hidden from assistive technology (the copy is alsoinert); the text is not a live region, so wrap the conversation inrole="log"to announce replies.
Technologies
- The pacer
use-stream-pacer.tsand thestream-reveal-*mixins instyle/mixins.scssare shared by the stream family. - Motion follows the streaming text of kobra.systems (
hue) and Beautiful UI (blur); the defaultauroracombines both. The caret is drawn from the Tuff logo. - Source:
packages/tuffex/packages/components/src/stream-text/.
查看源码
packages/tuffex/packages/components/src/stream-text/index.ts
Use cases
- An AI answer arriving token by token, in a chat, a panel, or a notification.
- Replaying a stored answer or a scripted demo at a readable pace, without moving the layout.
- A short generated sentence with sources, where each citation lands on its claim.
Related components
- StreamMarkdown renders whole Markdown documents as they stream, with the same presets and caret.
- CodeStream streams code.
- InlineCitation is the default citation chip.
- Sources lists the sources at the end of an answer.