Diff viewer component
The component that renders a source-code diff in a code-hosting surface: split (side-by-side) and unified (inline) modes, per-file sticky header with collapse + stats, expandable context hunks, line-level add/remove/ context styling, and anchors for inline review comments. Modeled after the GitHub diff view (Primer). Used by Koder Flow PR/commit/compare surfaces.
Status: v0.1.0 — Draft. Promoted from the GitHub Primer parity scan (metadocsstack #092). Live URL once rendered:
kds.koder.dev/<locale>/components/components-diff-viewer.html. Source: https://primer.style/ (diff / Blob view patterns).
R1 — Two modes
- Unified (inline): removed and added lines interleaved in one column;
default on narrow viewports.
- Split (side-by-side): old on the left, new on the right; default on
wide viewports.
- The mode is a user toggle, persisted per user (not per file). Both
modes render identical semantic line data (R3) — only layout differs.
R2 — Per-file block
Each changed file is its own block with a sticky header (stays pinned while scrolling that file's hunks) containing:
- file path (old→new on rename), with directory de-emphasized;
- change stats (
+a −b) using the add/remove semantic colors; - a collapse/expand toggle (collapsed files render header only);
- file-level status (added / modified / renamed / deleted / binary).
R3 — Line model
Every rendered line is exactly one of: context, added, removed, or hunk-header (the @@ … @@ separator). Add/remove use semantic fills + a leading gutter marker (+/−) so the distinction never relies on color alone (R7). Old and new line numbers render in gutters (both columns in split; two gutters in unified). Syntax highlighting is delegated to specs/components/code-block.kmd (the diff layer only adds the change overlay).
R4 — Expandable context
Between hunks, an expand-context control loads the hidden unchanged lines (expand up / down / all). Expansion fetches incrementally; the expanded lines render as context. Reaching file start/end disables the respective direction.
R5 — Inline comment anchors
- Any line exposes an affordance (on hover / keyboard focus) to start a
review comment thread anchored to that line (and, for multi-line selection, a line range).
- Anchored threads render inline beneath the line in both modes and are
owned by
specs/patterns/code-review.kmd(this component provides the anchor + slot, not the thread UI). - Anchors are stable to context expansion (anchored by line identity, not
scroll position).
R6 — Large & non-text diffs
- Files over a size/line threshold render collapsed by default with a
"Load diff" action (avoid freezing on huge diffs); the threshold is a surface setting, and truncation is always disclosed (no silent cap).
- Binary files show a "Binary file changed" notice; images show an
old/new visual compare (side-by-side / swipe), not a text diff.
R7 — Accessibility
- Add/remove conveyed by gutter marker + line-number column + semantic
fill (never color alone — WCAG 1.4.1).
- The diff is navigable by keyboard (next/prev changed hunk, next comment
thread); line numbers are programmatically associated with their lines.
- Screen-reader output announces line kind ("added line 42: …").
R8 — Tokens & i18n
- All fillsmarkers from Verge tokens (`specsthemesverge.kmd`); light
dark via the token layer.
- Chrome strings (stats label, "Load diff", "Expand", file status,
"Binary file changed") are translatable per
specs/i18n/contract.kmd; code content itself is never translated.
Não-escopo
- Syntax highlighting internals (
specs/components/code-block.kmd). - The review threaddecision UI (`specspatterns/code-review.kmd`).
- Diff computation / server-side hunking (Koder Flow backend).
- Word-level intra-line diff (optional v1 enhancement).