Skip to content

Commit 0610021

Browse files
authored
docs(readme): move OpenTUI component docs into dedicated page (#186)
1 parent dc46f0e commit 0610021

3 files changed

Lines changed: 142 additions & 61 deletions

File tree

README.md

Lines changed: 6 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@ Hunk is a review-first terminal diff viewer for agent-authored changesets, built
3333
npm i -g hunkdiff
3434
```
3535

36-
To use the reusable OpenTUI component in your own app:
37-
38-
```bash
39-
npm i hunkdiff
40-
```
41-
4236
Requirements:
4337

4438
- Node.js 18+
@@ -95,61 +89,6 @@ Hunk is optimized for reviewing a full changeset interactively.
9589

9690
## Advanced
9791

98-
### OpenTUI component
99-
100-
Hunk also publishes a reusable OpenTUI React diff component powered by the same terminal renderer that the app uses.
101-
102-
Runnable source examples live in [`examples/7-opentui-component`](examples/7-opentui-component/README.md).
103-
104-
Import it from `hunkdiff/opentui`:
105-
106-
```tsx
107-
import { HunkDiffView, parseDiffFromFile } from "hunkdiff/opentui";
108-
109-
const metadata = parseDiffFromFile(
110-
{
111-
cacheKey: "before",
112-
contents: "export const value = 1;\n",
113-
name: "example.ts",
114-
},
115-
{
116-
cacheKey: "after",
117-
contents: "export const value = 2;\nexport const added = true;\n",
118-
name: "example.ts",
119-
},
120-
{ context: 3 },
121-
true,
122-
);
123-
124-
<HunkDiffView
125-
diff={{
126-
id: "example",
127-
metadata,
128-
language: "typescript",
129-
path: "example.ts",
130-
}}
131-
layout="split"
132-
width={88}
133-
theme="midnight"
134-
/>;
135-
```
136-
137-
Public API:
138-
139-
- `diff?: { id, metadata, language?, path?, patch? }`
140-
- `layout?: "split" | "stack"`
141-
- `width: number`
142-
- `theme?: "graphite" | "midnight" | "paper" | "ember"`
143-
- `showLineNumbers?: boolean`
144-
- `showHunkHeaders?: boolean`
145-
- `wrapLines?: boolean`
146-
- `horizontalOffset?: number`
147-
- `highlight?: boolean`
148-
- `scrollable?: boolean`
149-
- `selectedHunkIndex?: number`
150-
151-
The component re-exports `parseDiffFromFile`, `parsePatchFiles`, and `FileDiffMetadata` from `@pierre/diffs` so callers can build the `metadata` input without adding a second diff dependency.
152-
15392
### Config
15493

15594
You can persist preferences to a config file:
@@ -270,6 +209,12 @@ hunk diff --agent-context notes.json
270209
hunk patch change.patch --agent-context notes.json
271210
```
272211

212+
### OpenTUI component
213+
214+
Hunk also publishes `HunkDiffView` from `hunkdiff/opentui` for embedding the same diff renderer in your own OpenTUI app.
215+
216+
See [docs/opentui-component.md](docs/opentui-component.md) for install, API, and runnable examples.
217+
273218
## Examples
274219

275220
Ready-to-run demo diffs live in [`examples/`](examples/README.md).

docs/opentui-component.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# OpenTUI component
2+
3+
`hunkdiff/opentui` exports `HunkDiffView`, a reusable terminal diff component built from the same renderer as the Hunk CLI.
4+
5+
Use it when you want Hunk's split or stack diff view inside your own OpenTUI app.
6+
7+
## Install
8+
9+
```bash
10+
npm i hunkdiff @opentui/core @opentui/react react
11+
```
12+
13+
`hunkdiff` declares OpenTUI and React as peer dependencies, so install them in your app.
14+
15+
## Quick start
16+
17+
```tsx
18+
import { createCliRenderer } from "@opentui/core";
19+
import { createRoot } from "@opentui/react";
20+
import { HunkDiffView, parseDiffFromFile } from "hunkdiff/opentui";
21+
22+
const metadata = parseDiffFromFile(
23+
{
24+
cacheKey: "before",
25+
contents: "export const value = 1;\n",
26+
name: "example.ts",
27+
},
28+
{
29+
cacheKey: "after",
30+
contents: "export const value = 2;\nexport const added = true;\n",
31+
name: "example.ts",
32+
},
33+
{ context: 3 },
34+
true,
35+
);
36+
37+
const renderer = await createCliRenderer({
38+
useAlternateScreen: true,
39+
useMouse: true,
40+
exitOnCtrlC: true,
41+
});
42+
const root = createRoot(renderer);
43+
44+
root.render(
45+
<HunkDiffView
46+
diff={{
47+
id: "example",
48+
metadata,
49+
language: "typescript",
50+
path: "example.ts",
51+
}}
52+
layout="split"
53+
width={88}
54+
theme="midnight"
55+
/>,
56+
);
57+
```
58+
59+
In a real app, derive `width` from your layout or `useTerminalDimensions()`.
60+
61+
## Building the `diff` input
62+
63+
`HunkDiffView` renders one file at a time. Pass a `diff` object shaped like this:
64+
65+
```ts
66+
type HunkDiffFile = {
67+
id: string;
68+
metadata: FileDiffMetadata;
69+
language?: string;
70+
path?: string;
71+
patch?: string;
72+
};
73+
```
74+
75+
### From before/after contents
76+
77+
Use `parseDiffFromFile(...)` when you already have the old and new file contents.
78+
79+
```tsx
80+
import { parseDiffFromFile } from "hunkdiff/opentui";
81+
82+
const metadata = parseDiffFromFile(beforeFile, afterFile, { context: 3 }, true);
83+
```
84+
85+
### From unified diff text
86+
87+
Use `parsePatchFiles(...)` when you already have a patch string.
88+
89+
```tsx
90+
import { parsePatchFiles } from "hunkdiff/opentui";
91+
92+
const parsed = parsePatchFiles(patchText, "example:patch", true);
93+
const metadata = parsed.flatMap((entry) => entry.files)[0];
94+
95+
if (!metadata) {
96+
throw new Error("Expected at least one diff file.");
97+
}
98+
```
99+
100+
## Props
101+
102+
| Prop | Type | Default | Notes |
103+
| ------------------- | ------------------------------------------------ | ------------ | ------------------------------------------------------------------------- |
104+
| `diff` | `HunkDiffFile` | `undefined` | File to render. When omitted, the component shows an empty-state message. |
105+
| `layout` | `"split" \| "stack"` | `"split"` | Chooses side-by-side or stacked rendering. |
106+
| `width` | `number` || Required content width in terminal columns. |
107+
| `theme` | `"graphite" \| "midnight" \| "paper" \| "ember"` | `"graphite"` | Matches Hunk's built-in themes. |
108+
| `showLineNumbers` | `boolean` | `true` | Toggles line-number columns. |
109+
| `showHunkHeaders` | `boolean` | `true` | Toggles `@@ ... @@` hunk header rows. |
110+
| `wrapLines` | `boolean` | `false` | Wraps long lines instead of clipping horizontally. |
111+
| `horizontalOffset` | `number` | `0` | Scroll offset for non-wrapped code rows. |
112+
| `highlight` | `boolean` | `true` | Enables syntax highlighting. |
113+
| `scrollable` | `boolean` | `true` | Set to `false` if your parent view owns scrolling. |
114+
| `selectedHunkIndex` | `number` | `0` | Highlights one hunk as the active target. |
115+
116+
## Other exports
117+
118+
- `parseDiffFromFile`
119+
- `parsePatchFiles`
120+
- `FileDiffMetadata`
121+
- `HUNK_DIFF_THEME_NAMES`
122+
- `HunkDiffThemeName`
123+
- `HunkDiffLayout`
124+
- `HunkDiffFile`
125+
- `HunkDiffViewProps`
126+
127+
`parseDiffFromFile`, `parsePatchFiles`, and `FileDiffMetadata` are re-exported from `@pierre/diffs` so you can build `metadata` without adding a second diff dependency.
128+
129+
## Examples
130+
131+
- Runnable demo overview: [`examples/README.md`](../examples/README.md)
132+
- Component demos: [`examples/7-opentui-component/README.md`](../examples/7-opentui-component/README.md)
133+
134+
The in-repo demos import from `../../src/opentui` so they run from source. Published consumers should import from `hunkdiff/opentui`.

examples/7-opentui-component/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
Two minimal OpenTUI apps that embed `HunkDiffView` directly.
44

5+
For package install and API details, see [OpenTUI component docs](../../docs/opentui-component.md).
6+
57
## Run
68

79
```bash

0 commit comments

Comments
 (0)