({
children = "",
reasoning: reasoningProp = "",
isStreaming = false,
caret,
repair = true,
sanitize = true,
memoizeBlocks = true,
caretHtml = DEFAULT_CARET,
sanitizeConfig,
className,
fallback = null,
thinkingLabel = "Thinking",
thinkingOpen,
reasoningPendingLabel = "Composing reply…",
...rest
}: StreamHtmlProps)
| 321 | ThinkingBlock.displayName = "ThinkingBlock"; |
| 322 | |
| 323 | export function StreamHtml({ |
| 324 | children = "", |
| 325 | reasoning: reasoningProp = "", |
| 326 | isStreaming = false, |
| 327 | caret, |
| 328 | repair = true, |
| 329 | sanitize = true, |
| 330 | memoizeBlocks = true, |
| 331 | caretHtml = DEFAULT_CARET, |
| 332 | sanitizeConfig, |
| 333 | className, |
| 334 | fallback = null, |
| 335 | thinkingLabel = "Thinking", |
| 336 | thinkingOpen, |
| 337 | reasoningPendingLabel = "Composing reply…", |
| 338 | ...rest |
| 339 | }: StreamHtmlProps): ReactElement { |
| 340 | const { content: streamContent, reasoning: streamReasoning } = useMemo(() => { |
| 341 | if (reasoningProp || !children.includes('"kind":"')) { |
| 342 | return { content: children, reasoning: reasoningProp }; |
| 343 | } |
| 344 | const split = splitStoredStreamText(children); |
| 345 | return { |
| 346 | content: split.content, |
| 347 | reasoning: reasoningProp || split.reasoning, |
| 348 | }; |
| 349 | }, [children, reasoningProp]); |
| 350 | |
| 351 | const reasoning = streamReasoning; |
| 352 | const htmlContent = streamContent; |
| 353 | |
| 354 | const showCaret = caret ?? isStreaming; |
| 355 | const stableRef = useRef<string[]>([]); |
| 356 | const hasReasoning = reasoning.length > 0; |
| 357 | const hasContent = htmlContent.length > 0; |
| 358 | const reasoningExpanded = |
| 359 | thinkingOpen ?? (isStreaming && hasReasoning && !hasContent); |
| 360 | |
| 361 | const { sanitizedStable, sanitizedLive, trackLive } = useMemo(() => { |
| 362 | const source = htmlContent ?? ""; |
| 363 | |
| 364 | if (!repair) { |
| 365 | const html = sanitize ? sanitizeHtml(source, sanitizeConfig) : source; |
| 366 | return { |
| 367 | sanitizedStable: [] as string[], |
| 368 | sanitizedLive: html, |
| 369 | trackLive: html, |
| 370 | }; |
| 371 | } |
| 372 | |
| 373 | const repaired = rehtml(source, { |
| 374 | splitBlocks: !isStreaming, |
| 375 | closeTags: !isStreaming, |
| 376 | }); |
| 377 | |
| 378 | const sanitizeBlock = (block: string) => |
| 379 | sanitize ? sanitizeHtml(block, sanitizeConfig) : block; |
| 380 |
nothing calls this directly
no test coverage detected