Diff View

A unified or side-by-side diff. Takes parsed hunks rather than a patch string, with parseUnifiedDiff exported alongside for when you only have the text.

src/components/ui/diff-view.tsx

About

From the component's own source, where it was written.

A unified or split diff.

Takes parsed hunks rather than a raw patch string: parsing unified-diff text is a separate concern with its own edge cases (renames, binary files, "\ No newline at end of file"), and baking a half-parser into a view component means every caller inherits its bugs. parseUnifiedDiff is exported alongside for the common case.

Split mode pairs deletions with insertions positionally within a hunk, which is what a side-by-side view actually shows — not a semantic word-level match, which needs a real diff algorithm and a lot more code than this earns.

Install

npx astralyx-ui add diff-view

Usage

import { DiffView, parseUnifiedDiff } from '@/components/ui/diff-view'

<DiffView
  file={{ path: 'src/lib/styles.ts', hunks: parseUnifiedDiff(patch) }}
  view="split"
/>

Composer

Change the props and the source below follows.

@@ -12,7 +12,9 @@ export const controlSize = {
sm: 'h-8 gap-1.5 px-3.5 text-sm',
md: 'h-9 gap-2 px-4.5 text-sm',
- lg: 'h-10 gap-2 px-6 text-sm',
+ lg: 'h-10 gap-2 px-6 text-sm rounded-[var(--radius-control-lg)]',
+ xl: 'h-12 gap-2.5 px-8 text-base',
} as const
export const buttonText = {
Props
tsx
<DiffView
  file={{ path: 'src/lib/styles.ts', hunks: parseUnifiedDiff(patch) }}
  view="unified"
  collapsible={true}
/>

Examples

Unified and split

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

DiffView

Extends ComponentProps<'div'>.

PropTypeDefaultDescription
fileDiffFilerequired{ path, previousPath?, status?, hunks }. Additions and deletions are counted from the hunks rather than passed in, so the header can never disagree with the body.
view'unified' | 'split''unified'Split pairs removals with additions positionally inside each hunk — what a side-by-side view actually shows, without a word-level diff algorithm.
collapsiblebooleantrueFold the file behind its header, for a review with many files.
defaultOpenbooleantrueFold the file behind its header, for a review with many files.

DiffViewList

Several files in one review, sharing a view mode.

Extends Omit<ComponentProps<'div'>, 'children'>.

PropTypeDefaultDescription
filesDiffFile[]required—
view'unified' | 'split''unified'Split pairs removals with additions positionally inside each hunk — what a side-by-side view actually shows, without a word-level diff algorithm.
childrenReactNode——

Functions

FunctionSignatureDescription
parseUnifiedDiff(patch: string) => DiffHunk[]Parses standard unified-diff text, tracking old and new line numbers across hunks.

Types

DiffLine

A unified or split diff.

FieldTypeDescription
type'add' | 'remove' | 'context' | 'meta'—
contentstring—
oldLine?number1-based line number in the old file.
newLine?number1-based line number in the new file.

DiffHunk

FieldTypeDescription
headerstring—
linesDiffLine[]—

DiffFile

FieldTypeDescription
pathstring—
previousPath?stringSet when the file was moved.
status?'modified' | 'added' | 'removed' | 'renamed'—
hunksDiffHunk[]—