react-tree-stream
Version:
Stream React trees recursively, LLM-style progressive rendering.
1 lines • 26.3 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.tsx","../src/TreeStream.tsx","../src/nested.ts","../src/plan.ts","../src/useSequentialScheduler.ts","../src/reducer.ts"],"sourcesContent":["export { TreeStream } from './TreeStream';\nexport type { TreeStreamProps } from './TreeStream';\nexport { default } from './TreeStream';\nexport { buildPlan, planSignature, type ExecutionUnit } from './plan';\nexport { isTreeStreamElement, STREAMING_MARKER } from './nested';\n","'use client';\n\nimport React, { useEffect, useMemo, useCallback, useRef, useId, useReducer } from 'react';\nimport { STREAMING_MARKER } from './nested';\nimport { buildPlan, planSignature, type ExecutionUnit } from './plan';\nimport { useSequentialScheduler } from './useSequentialScheduler';\nimport { initialStreamState, streamReducer } from './reducer';\n\n/**\n * TreeStream\n *\n * A client-only React component that renders its children incrementally over time.\n * It walks the provided React node tree into a linear execution plan of units:\n * - text units (streamed by word or character)\n * - instant units (regular React elements rendered immediately)\n * - nested stream units (child TreeStream elements, coordinated by onComplete)\n *\n * Contract (inputs/outputs):\n * - Props:\n * - as: optional polymorphic element type; use 'fragment' for no wrapper\n * - children: any renderable React nodes; fragments/arrays are flattened\n * - speed: number of tokens per tick (tokens are words or characters)\n * - interval: ms between ticks\n * - streamBy: 'word' | 'character' determines tokenization of text units\n * - autoStart: start streaming automatically when inputs/signature change\n * - onComplete: called after the final unit completes (including nested)\n * - DOM: adds data attributes for observability:\n * - data-tree-stream, data-streaming, data-complete\n * - SSR: client-only ('use client'); streaming occurs in the browser\n *\n * Notes:\n * - Nested TreeStream children have autoStart forced to true, and their\n * onComplete is composed so the parent resumes after the child completes.\n * - A stable \"plan signature\" is used to reset the stream only when structure\n * or text content changes; this limits unnecessary restarts.\n */\n\n// ExecutionUnit is now imported from ./plan\n\n/**\n * Props for TreeStream.\n * - speed: tokens per tick (>= 1). Tokens are words or characters per streamBy.\n * - interval: delay between ticks in ms.\n * - streamBy: tokenization strategy for text nodes.\n * - autoStart: if false, the component initializes idle until inputs change again or programmatically started in a future version.\n */\n/**\n * Core properties for the TreeStream component\n */\ntype OwnProps = {\n\t/**\n\t * Number of tokens to display per tick (must be >= 1).\n\t * Tokens are either words or characters based on the `streamBy` prop.\n\t * @default 5\n\t */\n\tspeed?: number;\n\t/**\n\t * Delay between ticks in milliseconds.\n\t * Controls the animation speed of the streaming effect.\n\t * @default 50\n\t */\n\tinterval?: number;\n\t/**\n\t * Tokenization strategy for text nodes.\n\t * - 'word': Text is split and streamed word by word\n\t * - 'character': Text is split and streamed character by character\n\t * @default 'word'\n\t */\n\tstreamBy?: 'word' | 'character';\n\t/**\n\t * Whether to automatically start streaming when the component mounts\n\t * or when inputs/signature change. If false, the component initializes\n\t * in an idle state.\n\t * @default true\n\t */\n\tautoStart?: boolean;\n\t/**\n\t * Callback invoked after all content (including nested TreeStream components)\n\t * has finished streaming.\n\t */\n\tonComplete?: () => void;\n};\n\ntype AsProp<E extends React.ElementType> = { as?: E };\ntype PropsToOmit<E extends React.ElementType> = keyof (AsProp<E> & OwnProps);\ntype PolymorphicProps<E extends React.ElementType> = AsProp<E> &\n\tOwnProps &\n\tOmit<React.ComponentPropsWithoutRef<E>, PropsToOmit<E>>;\ntype FragmentPropsGuard<E extends React.ElementType> = E extends typeof React.Fragment\n\t? { className?: never; style?: never }\n\t: {};\n\n/**\n * Props for the TreeStream component with polymorphic support.\n *\n * @template E - The element type for the wrapper component\n * @example\n * ```tsx\n * // Default div wrapper\n * <TreeStream>Content</TreeStream>\n *\n * // Custom element wrapper\n * <TreeStream as=\"section\">Content</TreeStream>\n *\n * // No wrapper (fragment)\n * <TreeStream as={React.Fragment}>Content</TreeStream>\n * ```\n */\nexport type TreeStreamProps<E extends React.ElementType = 'div'> = PolymorphicProps<E> & FragmentPropsGuard<E>;\n\n// Stable instance id for keys (SSR-friendly and deterministic)\n// Prefer useId over custom counters for readability and testability\n\n// Helper to detect fragment usage\nfunction isFragmentElementType(as: React.ElementType | undefined): as is typeof React.Fragment {\n\treturn as === React.Fragment;\n}\n\n// buildPlan and planSignature are imported from ./plan\n\n/**\n * TreeStream - A React component that renders content with a streaming animation effect.\n *\n * Renders children incrementally over time, creating a typewriter-like effect.\n * Supports text streaming (by word or character), instant rendering of React elements,\n * and nested TreeStream components with coordinated completion callbacks.\n *\n * @template E - The element type for the wrapper component (defaults to 'div')\n * @param props - The component props\n * @param props.as - Optional polymorphic element type. Use React.Fragment for no wrapper\n * @param props.children - React nodes to stream. Fragments and arrays are flattened\n * @param props.speed - Number of tokens to display per tick (default: 5)\n * @param props.interval - Milliseconds between ticks (default: 50)\n * @param props.streamBy - Tokenization strategy: 'word' or 'character' (default: 'word')\n * @param props.autoStart - Start streaming automatically on mount/change (default: true)\n * @param props.onComplete - Callback when streaming completes (including nested streams)\n *\n * @returns A React element that streams its content progressively\n *\n * @example\n * ```tsx\n * // Basic usage\n * <TreeStream speed={10} interval={30}>\n * Hello world! This text will stream in.\n * </TreeStream>\n *\n * // Character-by-character streaming\n * <TreeStream streamBy=\"character\" speed={1}>\n * Typing effect...\n * </TreeStream>\n *\n * // With completion callback\n * <TreeStream onComplete={() => console.log('Done!')}>\n * Content here\n * </TreeStream>\n *\n * // Nested streaming components\n * <TreeStream>\n * First part\n * <TreeStream>Nested content streams after parent</TreeStream>\n * Final part\n * </TreeStream>\n * ```\n */\nexport function TreeStream<E extends React.ElementType = 'div'>({\n\tas,\n\tchildren,\n\tspeed = 5,\n\tinterval = 50,\n\tstreamBy = 'word',\n\tautoStart = true,\n\tonComplete,\n\t...rest\n}: TreeStreamProps<E>) {\n\tconst instanceId = useId();\n\n\t// Keep latest onComplete in a ref to avoid effect resubscribes\n\tconst onCompleteRef = useRef<(() => void) | undefined>(onComplete);\n\tuseEffect(() => {\n\t\tonCompleteRef.current = onComplete;\n\t}, [onComplete]);\n\n\t// Build plan & a stable signature\n\tconst plan = useMemo(() => buildPlan(children), [children]);\n\tconst signature = useMemo(() => planSignature(plan), [plan]);\n\n\t// Store latest plan in a ref for the executor (avoids callback deps churn)\n\tconst latestPlanRef = useRef<ExecutionUnit[]>(plan);\n\tuseEffect(() => {\n\t\tlatestPlanRef.current = plan;\n\t}, [plan]);\n\n\t// Centralized scheduler for timers and run guards\n\tconst { schedule: scheduleNext, cancelAll, nextRunToken } = useSequentialScheduler();\n\n\t// Internal state managed via reducer\n\tconst [state, dispatch] = useReducer(streamReducer, initialStreamState);\n\tconst {\n\t\tunitIndex: currentUnit,\n\t\twaitingNested: isWaitingForNested,\n\t\trendered: renderedMap,\n\t\ttext,\n\t\tcomplete: isComplete,\n\t} = state;\n\tconst activeTextUnitRef = useRef<number | null>(text.activeUnit);\n\n\t// Executor (reads latest plan from ref; stable callback)\n\tconst runUnit = useCallback((unitIndex: number) => {\n\t\tconst currentPlan = latestPlanRef.current;\n\t\tif (unitIndex >= plan.length) {\n\t\t\tdispatch({ type: 'COMPLETE' });\n\t\t\tonCompleteRef.current?.();\n\t\t\treturn;\n\t\t}\n\t\tconst unit = currentPlan[unitIndex];\n\t\tif (!unit) return;\n\t\tswitch (unit.type) {\n\t\t\tcase 'text_stream': {\n\t\t\t\tconst units = streamBy === 'character' ? unit.content.split('') : unit.content.split(/(\\s+)/);\n\t\t\t\tactiveTextUnitRef.current = unitIndex;\n\t\t\t\tdispatch({ type: 'BEGIN_TEXT', unitIndex, tokens: units });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'instant_render': {\n\t\t\t\tdispatch({ type: 'INSTANT_RENDER', unitIndex, node: unit.content });\n\t\t\t\tconst next = unitIndex + 1;\n\t\t\t\tdispatch({ type: 'ADVANCE' });\n\t\t\t\tscheduleNext(() => runUnit(next), 0);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase 'nested_stream': {\n\t\t\t\t// Compose child's onComplete with parent advance\n\t\t\t\tconst child = unit.component;\n\t\t\t\tconst childExisting = (child.props as { onComplete?: () => void })?.onComplete as\n\t\t\t\t\t| (() => void)\n\t\t\t\t\t| undefined;\n\t\t\t\tconst composed = () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tchildExisting?.();\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tdispatch({ type: 'NESTED_DONE' });\n\t\t\t\t\t\tconst next = unitIndex + 1;\n\t\t\t\t\t\tdispatch({ type: 'ADVANCE' });\n\t\t\t\t\t\tscheduleNext(() => runUnit(next), 0);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t\tconst nestedWithCb = React.cloneElement(child, {\n\t\t\t\t\t...child.props,\n\t\t\t\t\tautoStart: true,\n\t\t\t\t\tonComplete: composed,\n\t\t\t\t});\n\t\t\t\tdispatch({ type: 'NESTED_START', unitIndex, node: nestedWithCb });\n\t\t\t\tbreak; // wait for nested to call back\n\t\t\t}\n\t\t}\n\t}, []);\n\n\t// Text tick\n\tuseEffect(() => {\n\t\tif (!text.streaming || text.tokens.length === 0) return;\n\t\tif (text.index >= text.tokens.length) {\n\t\t\tdispatch({ type: 'END_TEXT' });\n\t\t\tconst next = currentUnit + 1;\n\t\t\tdispatch({ type: 'ADVANCE' });\n\t\t\tscheduleNext(() => runUnit(next), 0);\n\t\t\treturn;\n\t\t}\n\t\tscheduleNext(() => {\n\t\t\tconst step = Math.max(1, speed ?? 1);\n\t\t\tconst nextIndex = Math.min(text.index + step, text.tokens.length);\n\t\t\tconst textContent = text.tokens.slice(0, nextIndex).join('');\n\t\t\tdispatch({ type: 'TEXT_TICK', nextIndex, content: textContent });\n\t\t}, Math.max(0, interval ?? 0));\n\t}, [text.streaming, text.tokens, text.index, speed, interval, currentUnit, runUnit, scheduleNext]);\n\n\t// Reset ONLY when the signature or autoStart change\n\tuseEffect(() => {\n\t\tnextRunToken();\n\t\tactiveTextUnitRef.current = null;\n\t\tdispatch({ type: 'RESET' });\n\n\t\tconst planLen = latestPlanRef.current.length;\n\t\tif (planLen === 0) {\n\t\t\tdispatch({ type: 'COMPLETE' });\n\t\t\tonCompleteRef.current?.();\n\t\t\treturn;\n\t\t}\n\t\tif (autoStart) runUnit(0);\n\n\t\treturn () => {\n\t\t\tcancelAll();\n\t\t};\n\t}, [signature, autoStart, runUnit, nextRunToken, cancelAll]);\n\n\t// Memoise element creation\n\tconst element = useMemo(() => {\n\t\tconst children = Array.from(renderedMap.entries()).map(([unitIndex, content]) => (\n\t\t\t<React.Fragment key={`${instanceId}:u${unitIndex}`}>{content}</React.Fragment>\n\t\t));\n\n\t\tif (isFragmentElementType(as)) {\n\t\t\treturn <React.Fragment>{children}</React.Fragment>;\n\t\t}\n\n\t\t// The type guard ensures `as` is not Fragment here.\n\t\tconst Element = (as || 'div') as React.ElementType;\n\t\tconst { className, style, ...elementProps } = rest as {\n\t\t\tclassName?: string;\n\t\t\tstyle?: React.CSSProperties;\n\t\t\t[key: string]: unknown;\n\t\t};\n\t\tconst props = {\n\t\t\t...elementProps,\n\t\t\tclassName,\n\t\t\tstyle,\n\t\t\t'data-tree-stream': true,\n\t\t\t'data-streaming': text.streaming || isWaitingForNested,\n\t\t\t'data-complete': isComplete,\n\t\t};\n\n\t\treturn <Element {...props}>{children}</Element>;\n\t}, [as, rest, text.streaming, isWaitingForNested, isComplete, renderedMap, instanceId]);\n\n\treturn element;\n}\n\n/* mark component for wrapped detection */\n(TreeStream as unknown as Record<string | symbol, unknown>)[STREAMING_MARKER] = true;\nTreeStream.displayName = 'TreeStream';\n\nexport default TreeStream;\n","import React from 'react';\n\n/** Marker symbol placed on the component function to detect wrappers. */\nexport const STREAMING_MARKER = Symbol.for('react-tree-stream/TreeStream');\n\n/**\n * isTreeStreamElement\n *\n * Detect whether a React element is a TreeStream component, even if wrapped\n * by React.memo or forwardRef. We check the function itself, .type for memo,\n * and .render for forwardRef. As a fallback we also check displayName.\n */\nexport function isTreeStreamElement(el: React.ReactElement): boolean {\n\tconst t = el.type as unknown as {\n\t\t[STREAMING_MARKER]?: boolean;\n\t\ttype?: { [STREAMING_MARKER]?: boolean };\n\t\trender?: { [STREAMING_MARKER]?: boolean };\n\t\tdisplayName?: string;\n\t};\n\treturn Boolean(\n\t\tt?.[STREAMING_MARKER] ||\n\t\t\tt?.type?.[STREAMING_MARKER] || // React.memo\n\t\t\tt?.render?.[STREAMING_MARKER] || // forwardRef\n\t\t\tt?.displayName === 'TreeStream',\n\t);\n}\n","import React from 'react';\nimport { isTreeStreamElement } from './nested';\n\n/**\n * Execution units produced from children to drive the streaming executor.\n * - text_stream: a text node that will be tokenized and streamed\n * - instant_render: any non-stream Tree element rendered immediately\n * - nested_stream: a nested TreeStream element coordinated by onComplete\n */\nexport type ExecutionUnit =\n\t| { type: 'text_stream'; content: string }\n\t| { type: 'instant_render'; content: React.ReactElement }\n\t| { type: 'nested_stream'; component: React.ReactElement };\n\n/**\n * buildPlan\n *\n * Convert an arbitrary React node tree into a flat execution plan.\n *\n * Inputs:\n * - node: any React renderable input (string/number/elements/arrays/fragments)\n *\n * Outputs:\n * - Array of ExecutionUnit preserving in-order appearance from the tree\n *\n * Rules:\n * - Strings/numbers become text stream units (empty strings are skipped)\n * - Fragments/arrays are flattened recursively\n * - Elements marked as TreeStream become nested stream units\n * - All other elements are instant render units\n *\n * Notes/edge cases:\n * - null/undefined/boolean nodes are ignored\n * - For strings we keep original content (including whitespace), but empty\n * strings after trim() are ignored to avoid no-op streaming units\n */\nexport function buildPlan(node: React.ReactNode): ExecutionUnit[] {\n\tif (node == null || node === false || node === true) return [];\n\tif (typeof node === 'string') return node.trim() ? [{ type: 'text_stream', content: node }] : [];\n\tif (typeof node === 'number') return [{ type: 'text_stream', content: String(node) }];\n\tif (Array.isArray(node)) return node.flatMap(buildPlan);\n\tif (React.isValidElement(node)) {\n\t\tif (node.type === React.Fragment) return buildPlan(node.props?.children);\n\t\tif (isTreeStreamElement(node)) return [{ type: 'nested_stream', component: node }];\n\t\treturn [{ type: 'instant_render', content: node }];\n\t}\n\treturn [];\n}\n\n/**\n * planSignature\n *\n * Create a stable string signature for a plan that captures structural shape\n * and text content for text units. This is used to decide when to reset/run.\n *\n * Implementation detail:\n * - text_stream includes its content to re-run when text changes\n * - instant_render and nested_stream capture only their type (not identity)\n */\nexport function planSignature(plan: ExecutionUnit[]): string {\n\treturn JSON.stringify(\n\t\tplan.map((u) => {\n\t\t\tswitch (u.type) {\n\t\t\t\tcase 'text_stream':\n\t\t\t\t\treturn ['T', u.content];\n\t\t\t\tcase 'nested_stream':\n\t\t\t\t\treturn ['N'];\n\t\t\t\tcase 'instant_render':\n\t\t\t\t\treturn ['I'];\n\t\t\t}\n\t\t}),\n\t);\n}\n","import { useCallback, useEffect, useRef } from 'react';\n\n/**\n * useSequentialScheduler\n *\n * Centralizes setTimeout scheduling with guarantees:\n * - Only callbacks scheduled in the latest run execute (run-token guard)\n * - All timers are cleared on unmount\n * - cancelAll() clears any pending timers for the current run\n */\nexport function useSequentialScheduler() {\n\tconst runIdRef = useRef(0);\n\tconst timersRef = useRef<ReturnType<typeof setTimeout>[]>([]);\n\n\tconst cancelAll = useCallback(() => {\n\t\tfor (const t of timersRef.current) clearTimeout(t);\n\t\ttimersRef.current = [];\n\t}, []);\n\n\tconst nextRunToken = useCallback(() => {\n\t\trunIdRef.current += 1;\n\t\tcancelAll();\n\t\treturn runIdRef.current;\n\t}, [cancelAll]);\n\n\tconst schedule = useCallback((fn: () => void, delay = 0) => {\n\t\tconst token = runIdRef.current;\n\t\tconst t = setTimeout(() => {\n\t\t\tif (runIdRef.current === token) fn();\n\t\t}, Math.max(0, delay));\n\t\ttimersRef.current.push(t);\n\t\treturn t;\n\t}, []);\n\n\tuseEffect(() => () => cancelAll(), [cancelAll]);\n\n\treturn { schedule, cancelAll, nextRunToken };\n}\n\nexport type SequentialScheduler = ReturnType<typeof useSequentialScheduler>;\n","import React from 'react';\n\nexport interface StreamState {\n\tunitIndex: number;\n\twaitingNested: boolean;\n\trendered: Map<number, React.ReactNode>;\n\ttext: {\n\t\ttokens: string[];\n\t\tindex: number;\n\t\tactiveUnit: number | null;\n\t\tstreaming: boolean;\n\t};\n\tcomplete: boolean;\n}\n\nexport type StreamAction =\n\t| { type: 'RESET' }\n\t| { type: 'START' }\n\t| { type: 'BEGIN_TEXT'; unitIndex: number; tokens: string[] }\n\t| { type: 'TEXT_TICK'; nextIndex: number; content: string }\n\t| { type: 'END_TEXT' }\n\t| { type: 'ADVANCE' }\n\t| { type: 'INSTANT_RENDER'; unitIndex: number; node: React.ReactNode }\n\t| { type: 'NESTED_START'; unitIndex: number; node: React.ReactNode }\n\t| { type: 'NESTED_DONE' }\n\t| { type: 'COMPLETE' };\n\nexport const initialStreamState: StreamState = {\n\tunitIndex: 0,\n\twaitingNested: false,\n\trendered: new Map(),\n\ttext: { tokens: [], index: 0, activeUnit: null, streaming: false },\n\tcomplete: false,\n};\n\nexport function streamReducer(state: StreamState, action: StreamAction): StreamState {\n\tswitch (action.type) {\n\t\tcase 'RESET':\n\t\t\treturn initialStreamState;\n\t\tcase 'START':\n\t\t\treturn { ...state };\n\t\tcase 'BEGIN_TEXT': {\n\t\t\tconst rendered = new Map(state.rendered);\n\t\t\tif (!rendered.has(action.unitIndex)) rendered.set(action.unitIndex, '');\n\t\t\treturn {\n\t\t\t\t...state,\n\t\t\t\ttext: {\n\t\t\t\t\ttokens: action.tokens,\n\t\t\t\t\tindex: 0,\n\t\t\t\t\tactiveUnit: action.unitIndex,\n\t\t\t\t\tstreaming: true,\n\t\t\t\t},\n\t\t\t\trendered,\n\t\t\t};\n\t\t}\n\t\tcase 'TEXT_TICK': {\n\t\t\tconst rendered = new Map(state.rendered);\n\t\t\tconst u = state.text.activeUnit;\n\t\t\tif (u != null) rendered.set(u, action.content);\n\t\t\treturn { ...state, text: { ...state.text, index: action.nextIndex }, rendered };\n\t\t}\n\t\tcase 'END_TEXT': {\n\t\t\treturn { ...state, text: { ...state.text, streaming: false } };\n\t\t}\n\t\tcase 'ADVANCE': {\n\t\t\treturn { ...state, unitIndex: state.unitIndex + 1 };\n\t\t}\n\t\tcase 'INSTANT_RENDER': {\n\t\t\tconst rendered = new Map(state.rendered);\n\t\t\trendered.set(action.unitIndex, action.node);\n\t\t\treturn { ...state, rendered };\n\t\t}\n\t\tcase 'NESTED_START': {\n\t\t\tconst rendered = new Map(state.rendered);\n\t\t\trendered.set(action.unitIndex, action.node);\n\t\t\treturn { ...state, waitingNested: true, rendered };\n\t\t}\n\t\tcase 'NESTED_DONE': {\n\t\t\treturn { ...state, waitingNested: false };\n\t\t}\n\t\tcase 'COMPLETE':\n\t\t\treturn { ...state, complete: true };\n\t}\n}\n"],"mappings":"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","names":["import_react","React","import_react","React","children"]}