Locara
← All components Editors

DiffView

Accept-per-hunk diff in three modes: unified (default), split (review-pane), prose (Granola gray-AI / black-user).

Inspired by Cursor inline diff, Granola enhanced-notes diff, GitHub unified format.

Preview

What it looks like.

Switch between unified / split / before-only / after-only.
src/lib/summarise.ts+56
@@ −1, +1 @@
1function summarise(items: string[]): string {
2 // Switched to a guard + .join() — 4× faster on long arrays
3 // and avoids the trailing newline footgun.
4 if (!items.length) return ''
5 return items.join('\n')
1function summarise(items) {
2 let out = ''
3 for (let i = 0; i < items.length; i++) {
4 out += items[i] + '\n'
5 }
6 return out
76}

Live — the real component, scoped to this frame.

Prose mode (Granola)
Meeting summary
The team discussed shipping the new transcription pipeline by Friday.
There were concerns about model accuracy.
Sarah raised concerns about model accuracy on accented English and proposed an evaluation pass before launch.
Usage

Drop it into your app.

import { DiffView } from '@locara/components'

<DiffView
  before={originalCode}
  after={aiSuggestedCode}
  mode="unified"
  title="apps/transcribe/src/main.tsx"
  onAcceptHunk={(i) => applyHunk(i)}
  onRejectHunk={(i) => discardHunk(i)}
  onAcceptAll={() => applyAll()}
  onRejectAll={() => discardAll()}
/>

Or copy the source into your repo: locara add diff-view

Design notes

Why it works this way.

LCS-based line diff under the hood. The `prose` mode uses Granola's typographic-only treatment (gray AI / black user, strikethrough on deletions) instead of green/red — much friendlier for natural language. Accept-per-hunk is the load-bearing affordance: AI edits should never be all-or-nothing.