Skip to content

Latest commit

 

History

History
82 lines (61 loc) · 2.57 KB

File metadata and controls

82 lines (61 loc) · 2.57 KB

markstream-react

React renderer that consumes the structured AST output from stream-markdown-parser and renders it with lightweight semantic HTML components. This is the React counter-part to the Vue renderer that powers markstream-vue.

Development

pnpm --filter markstream-react dev

Build

pnpm --filter markstream-react build
pnpm --filter markstream-react build:analyze
pnpm --filter markstream-react size:check

Usage

import NodeRenderer from 'markstream-react'
import 'markstream-react/index.css'

export default function Article({ markdown }: { markdown: string }) {
  return (
    <NodeRenderer content={markdown} />
  )
}

If your app scales root font size on mobile (html / body), use markstream-react/index.px.css to prevent rem-based global scaling side effects.

You can also pass a pre-parsed nodes array if you already have AST data.

Bundle size notes

  • Optional peers are not bundled; install only what you use (stream-monaco, stream-markdown, mermaid, katex, etc.).
  • Infrequent language icons are split into an async chunk and loaded on demand.
  • To avoid first-hit fallback icons, preload once when the app is idle:
import { preloadExtendedLanguageIcons } from 'markstream-react'

if (typeof window !== 'undefined')
  void preloadExtendedLanguageIcons()

Tailwind

  • Non-Tailwind projects: keep importing markstream-react/index.css (includes precompiled utilities for the renderer).
  • Tailwind projects (avoid duplicate utilities): import markstream-react/index.tailwind.css and add require('markstream-react/tailwind') to your tailwind.config.js content.

Custom components (e.g. <thinking>)

Custom tag-like blocks are exposed as nodes with type: 'thinking' (the tag name, no angle brackets) when you register the tag in customHtmlTags or register a custom component mapping for it.

import type { NodeComponentProps } from 'markstream-react'
import NodeRenderer, { setCustomComponents } from 'markstream-react'

function ThinkingNode(props: NodeComponentProps<{ type: 'thinking', content: string }>) {
  const { node, ctx } = props
  return (
    <div className="thinking-node">
      <div className="thinking-title">Thinking</div>
      <NodeRenderer
        content={node.content}
        customId={ctx?.customId}
        isDark={ctx?.isDark}
        typewriter={false}
        batchRendering={false}
        deferNodesUntilVisible={false}
        viewportPriority={false}
        maxLiveNodes={0}
      />
    </div>
  )
}

setCustomComponents('chat', { thinking: ThinkingNode })