authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-20 01:17:08-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-03-20 14:11:08-07:00
log5b921620c94fade38cd72a34fe2e1d195ef19cb8
treec14a05d2bcc63d21b1adda5578cfb1b8d26e1387
parent704609c6289c855a7653a8bd26a70e159da97959
signaturebadge-check Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs

fix: readme tidying


2 files changed, 23 insertions(+), 4 deletions(-)

README.md+22-3
...@@ -25,16 +25,25 @@ to Streamdown:...@@ -25,16 +25,25 @@ to Streamdown:
25 as adjacent content changes. This is done to preserve remounts for things like25 as adjacent content changes. This is done to preserve remounts for things like
26 custom `<a>` tags or other components. (For example, if a custom `<a>` fetches26 custom `<a>` tags or other components. (For example, if a custom `<a>` fetches
27 previewing data and provides a hover card, that card won't flicker).27 previewing data and provides a hover card, that card won't flicker).
28- **Better Prediction**: While optimizing edge cases, the prediction system became
29 better than the Streamdown one on accident.
28- **Headless UI**: No built in styles or components, bring your own CSS to blend30- **Headless UI**: No built in styles or components, bring your own CSS to blend
29 your markdown with your existing theme. `@clo/react-markdown` simply takes in31 your markdown with your existing theme. `@clo/react-markdown` simply takes in
30 your existing `unified` pipeline and works off of that.32 your existing `unified` pipeline and works off of that.
31- **Easy to Audit**: ~850 lines of TypeScript. Main dependency is [unified].33- **Easy to Audit**: Only ~1000 lines of modern TypeScript. 4 total files.
3234
33[Streamdown]: https://streamdown.ai35[Streamdown]: https://streamdown.ai
34[unified]: https://unifiedjs.com/36[unified]: https://unifiedjs.com/
3537
36## Getting Started38## Getting Started
3739
40Install off of the [JSR package](https://jsr.io/clo/react-markdown):
41
42```sh
43npx jsr add @clo/react-markdown
44pnpm add jsr:@clo/react-markdown
45```
46
38```tsx47```tsx
39import { Markdown } from "@clo/react-markdown";48import { Markdown } from "@clo/react-markdown";
40import remarkGfm from "remark-gfm";49import remarkGfm from "remark-gfm";
...@@ -70,6 +79,15 @@ export function HelloWorld() {...@@ -70,6 +79,15 @@ export function HelloWorld() {
70}79}
71```80```
7281
82If you want to play with the example project, which offers a comparison to
83Streamdown and the non-memoized `react-markdown` package.
84
85```
86git clone https://git.paperclover.net/clo/react-markdown
87cd react-markdown
88pnpm demo # auto-install
89```
90
73## Architecture91## Architecture
7492
75The `Markdown` component is built out of a memoizer which uses the following tricks to improve performance:93The `Markdown` component is built out of a memoizer which uses the following tricks to improve performance:
...@@ -89,7 +107,8 @@ The `Markdown` component is built out of a memoizer which uses the following tri...@@ -89,7 +107,8 @@ The `Markdown` component is built out of a memoizer which uses the following tri
89 it means any places that might have used a reference link may now have to107 it means any places that might have used a reference link may now have to
90 reflect it.108 reflect it.
91- After all that, a special AST -> React node transform is used that diffs the109- After all that, a special AST -> React node transform is used that diffs the
92 new ast with the last ast, reusing React nodes whenever possible. This is what110 new ast with the last ast, reusing React nodes whenever possible. It supports
93 prevents most rerenders.111 nested children as well as re-ordering top level blocks. This is what prevents
112 most rerenders and is the "secret sauce".
94113
95All put together, basically nothing rerenders except what actually changed, and the document is beautiful.114All put together, basically nothing rerenders except what actually changed, and the document is beautiful.
package.json+1-1
...@@ -6,7 +6,7 @@...@@ -6,7 +6,7 @@
6 "./Predict": "./src/Predict.ts"6 "./Predict": "./src/Predict.ts"
7 },7 },
8 "scripts": {8 "scripts": {
9 "demo": "vite dev",9 "demo": "pnpm install && vite dev",
10 "all": "pnpm --parallel fmt && pnpm --stream '/check|test$/'",10 "all": "pnpm --parallel fmt && pnpm --stream '/check|test$/'",
11 "test": "vitest",11 "test": "vitest",
12 "check": "oxlint --react-plugin --vitest-plugin --type-aware --type-check .",12 "check": "oxlint --react-plugin --vitest-plugin --type-aware --type-check .",