Skip to content

Rewrite renderer as component registry, expand token support - #1

Merged
exzos28 merged 2 commits into
mainfrom
refactor/renderer-rewrite
Aug 19, 2026
Merged

Rewrite renderer as component registry, expand token support#1
exzos28 merged 2 commits into
mainfrom
refactor/renderer-rewrite

Conversation

@exzos28

@exzos28 exzos28 commented Aug 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Replaces the monolithic switch-based renderer with per-token components wired through a shared context (components/styles overrides, onLinkPress/onImagePress, renderNode).
  • Adds support for fenced code blocks, images, tables, hr, and ordered/nested/task lists with checkboxes.
  • Breaking API changes: text prop → value; rules prop → components with a new { token, children, props, key } signature — props carries what the default renderer would spread onto its host element (style, onPress, ...) so an override can extend the default instead of reimplementing it.

Bugs fixed (found via visual diffing against a plain-HTML CommonMark reference)

  • Blank-line space tokens were rendered as literal newlines, doubling the gap between blocks on top of margin-based spacing.
  • Soft line breaks inside a paragraph weren't collapsed to a space — RN's <Text> (unlike HTML) rendered the raw \n as a real line break.
  • Nested lists inherited full block-level vertical margins, and a list_item ending in a nested list double-counted its own trailing margin.
  • image defaulted to width: '100%' inside an inline Text context, which visually centered it instead of flowing it left like normal inline content.
  • Image's resizeMode was hardcoded as a prop, shadowing any styles.image.resizeMode override.
  • blockquote had no visual fill (just an indent) — added a left border + background.

Test plan

  • yarn test — 34 component/unit tests (Jest + @testing-library/react-native), including a regression for every fix above
  • yarn test:perf — Reassure perf harness added for the full-document render path
  • yarn typecheck, yarn lint, yarn prepare (bob build) all clean
  • Visually verified in example/ (expo web) against a plain-HTML CommonMark reference render

🤖 Generated with Claude Code

exzos28 and others added 2 commits August 19, 2026 23:25
Replaces the single 500-line switch in index.tsx with per-token renderer
components wired through a shared context (styles/components overrides,
onLinkPress/onImagePress, renderNode). Adds support for fenced code blocks,
images, tables, hr, and ordered/nested/task lists with checkboxes.

Breaking API changes: `text` prop -> `value`, `rules` prop -> `components`
(new signature: `{ token, children, props, key }`, where `props` carries
what the default renderer would spread onto its host element so overrides
can extend rather than reimplement default behavior).

Fixes found via visual diffing against a plain-HTML CommonMark reference:
- blank-line `space` tokens were rendered as literal newlines, doubling
  the gap between blocks on top of margin-based spacing
- soft line breaks inside a paragraph weren't collapsed to a space, so RN's
  <Text> (unlike HTML) rendered them as real line breaks
- nested lists inherited full block-level vertical margins, and a list_item
  ending in a nested list double-counted its own trailing margin
- image defaulted to width: '100%' inside an inline Text context, which
  visually centered it instead of flowing it left like inline content
- Image's resizeMode was hardcoded as a prop, shadowing any
  styles.image.resizeMode override
- blockquote had no visual fill (just an indent), unlike common renderers

Adds Jest + @testing-library/react-native component tests (34, incl.
regressions for every fix above) and a Reassure perf-test harness
(yarn test:perf) for the full-document render path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same rescaffold as react-native-qr-svg: rebuilt from
create-react-native-library@latest (Expo ~55, RN 0.83.10, React 19.2.0,
yarn 4.11) instead of hand-patching the old toolchain, ESM-only build
output (no more commonjs target).

All library source (including renderers/, __fixtures__, __tests__,
__perf__), README, and the example app were ported over as-is. What
the new toolchain required to change:

- src/createStyles.ts: RN's StyleSheet.create() no longer returns
  StyleSheet.NamedStyles<T> (removed) - create() now returns
  Readonly<S> matching the input shape directly, so
  createStyles/mergeNamedStyles are typed against StyleSheetRecord /
  Record<string, ViewStyle | TextStyle | ImageStyle> instead
- src/getStyle.ts: dropped an explicit TextStyle annotation on a
  StyleSheet.flatten() result - RN's flatten() return type is
  generically computed from its input and no longer structurally
  matches our own TextStyle reference closely enough for TS
- tests: @testing-library/react-native 14's render/rerender/fireEvent
  are async now (await them); no more UNSAFE_getAllByType - View/Text
  instances are queried via container.queryAll(i => i.type === 'View')
  instead; test globals imported explicitly from @jest/globals
- reassure (test:perf) carried over: added back as a devDependency
  and script, its perf-test file's `test` global imported from
  @jest/globals too

Verified: typecheck, lint, and all 34 tests pass.
@exzos28
exzos28 merged commit cecf4ac into main Aug 19, 2026
6 checks passed
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