File Diff
A file's changes as a real <table> inside a<details>. A diff is tabular data — old line number, new line number, change marker, content — so it's a table, which is also what gives each row a readable structure instead of a wall of pre-formatted text.
packages/react/src/utils/stickToBottom.ts+0−0
| Old line | New line | Change | Content |
|---|---|---|---|
| @ | @@ -80,7 +80,11 @@ export class StickToBottomController | ||
| 80 | 80 | scrollToBottom(behavior = "instant") { |
Playground
Toggle every adjustable prop and watch the component — and the code — update live.
src/utils/stickToBottom.ts+1−1
| Old line | New line | Change | Content |
|---|---|---|---|
| @ | @@ -80,3 +80,4 @@ | ||
| 80 | 80 | scrollToBottom(behavior) { | |
| 81 | − | this.viewport.scrollTo({ top: max }); | |
| 81 | + | this.viewport.scrollTop = max; | |
| 82 | 82 | } |
Same component — Kernel look stripped. See Platforms.
Usage
<FileDiff
path="src/utils/stickToBottom.ts"
showLineNumbers={true}
streaming={false}
collapseOnComplete={false}
rows={[
{ kind: "hunk", content: "@@ -80,3 +80,4 @@" },
{ kind: "context", oldLine: 80, newLine: 80, content: " scrollToBottom(behavior) {" },
{ kind: "remove", oldLine: 81, content: " this.viewport.scrollTo({ top: max });" },
{ kind: "add", newLine: 81, content: " this.viewport.scrollTop = max;" },
]}
/><kernel-file-diff
id="diff"
path="src/utils/stickToBottom.ts"
></kernel-file-diff>
<script type="module">
document.getElementById("diff").rows = [
{ kind: "hunk", content: "@@ -80,3 +80,4 @@" },
{ kind: "remove", oldLine: 81, content: " this.viewport.scrollTo({ top: max });" },
{ kind: "add", newLine: 81, content: " this.viewport.scrollTop = max;" },
];
</script>Props
| Prop | Type | Default |
|---|---|---|
path | ReactNode | required |
rows | DiffRow[] | required |
streaming | boolean | false |
showLineNumbers | boolean | true |
collapseOnComplete | boolean | false |
defaultOpen | boolean | true |
additions / deletions | number | derived |
A DiffRow is{ kind, oldLine?, newLine?, content?, tokens? }, wherekind is "add", "remove","context" or "hunk", and tokens is the same CodeToken shapeCode Block takes — so one highlighter serves both. Counts are derived from the rows; passadditions and deletions yourself whenrows is a window onto a larger diff.
Motion
Rows fade in once, on insert, so a streaming diff reads as lines landing — and because that's a keyframe animation on a freshly inserted row, it can't re-run when the rows above it re-render. WithcollapseOnComplete, the disclosure holds open while rows arrive and settles closed a beat after they stop, so the finished change registers before it folds away. That fires only on the streaming edge, so a diff you reopened by hand is never slammed shut by the next re-render — the same rule Reasoning uses.
Accessibility
- The
+/−marker stays in the DOM as text. Colour alone doesn't tell you whether a line was added or removed, and a diff where that's ambiguous is a diff you can't read. - Line numbers live in their own cells rather than in the content, and are unselectable, so selecting and copying a diff copies the code and not the gutter.
- The table carries a visually hidden caption naming the file and its counts, and hidden column headers, so the row structure is announced without printing a header row nobody needs to see.