Skip to content

fix(streamdown-rn): resolve React 19 runtime crash and type compatibility#23

Open
thedonmon wants to merge 3 commits intodarkresearch:mainfrom
thedonmon:main
Open

fix(streamdown-rn): resolve React 19 runtime crash and type compatibility#23
thedonmon wants to merge 3 commits intodarkresearch:mainfrom
thedonmon:main

Conversation

@thedonmon
Copy link

Summary

Fixes two bugs that prevent streamdown-rn from working in Expo 54 consumer apps, plus improves the incomplete markdown handler.

Bug 1: Runtime crash — "A React Element from an older version of React"

The dist/ files shipped raw JSX because tsconfig.json inherited "jsx": "react-native" (equivalent to "preserve"). This works when the consumer's bundler resolves react from the project root, but with bun's symlinked node_modules, Metro resolves react/jsx-runtime from inside .bun/streamdown-rn@0.2.1+.../ instead of the project root — loading a different React copy at runtime.
Fix: Set "jsx": "react-jsx" in packages/streamdown-rn/tsconfig.json so the compiled output imports { jsx } from "react/jsx-runtime" directly, ensuring Metro resolves a single React instance.

Bug 2: TypeScript error — "'StreamdownRN' cannot be used as a JSX component"

Consumer projects with @types/react@~19.1.x (which Expo 54 installs) get a type error because React.FC resolves to different return types across @types/react minor versions. The exported React.FC<StreamdownRNProps> from 19.0.x is incompatible with 19.1.x's stricter ReactNode definition.
Fix: Change export const StreamdownRN: React.FC<Props> = React.memo(...) to export const StreamdownRN = React.memo<Props>(...). The emitted type becomes React.NamedExoticComponent<Props> which is stable across @types/react versions.

Improvement: Align incomplete markdown handler with remend patterns

Ported several missing features from the upstream remend package into core/incomplete.ts:

  • Backslash escape awareness (\*, \_, \~, etc.)
  • Word-internal marker detection (hello_world, file*name no longer trigger emphasis)
  • Underscore emphasis (_italic_, __bold__)
  • Math block tracking ($inline$, $$block$$) — skips emphasis inside math
  • Image handling (![alt](url)) — strips incomplete images, auto-closes in URL phase
  • List marker awareness (* item not treated as italic)
  • 55 new tests covering all additions

Changes

  • packages/streamdown-rn/tsconfig.json"jsx": "react-jsx"
  • packages/streamdown-rn/src/StreamdownRN.tsx — remove React.FC annotation
  • packages/streamdown-rn/src/core/types.ts — add inMathBlock/inInlineMath to state
  • packages/streamdown-rn/src/core/incomplete.ts — new features listed above
  • packages/streamdown-rn/src/__tests__/incomplete.test.ts — 55 new tests
    All 256 tests pass. Type check and build succeed.

…tterns

Add backslash escape awareness, underscore emphasis (_/__), math block
tracking ($/$$), image handling (![]()), word-internal marker detection,
and list marker awareness. 55 new tests covering all additions.
Replace React.FC<Props> with React.memo<Props> so the exported type
is NamedExoticComponent instead of FC, avoiding cross-version
@types/react ReactNode mismatch.
…ntime

The dist/ was shipping raw JSX (jsx: preserve/react-native), relying on
the consumer's bundler to transform it. With bun's symlinked node_modules,
Metro could resolve react/jsx-runtime from a different path, causing the
'older version of React' runtime error. Compiling to react-jsx ensures
the dist imports from react/jsx-runtime directly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant