// Adapted from jalcoui (MIT) — github.com/jal-co/ui 'use client'; import * as React from 'react'; import type { Language, PrismTheme } from 'prism-react-renderer'; import { Virtuoso } from 'react-virtuoso'; import { cn } from '@djangocfg/ui-core/lib'; import { DIFF_TONE_CLASSES, type DiffLine } from '../types'; import { DiffLineContent } from './DiffLineContent'; interface UnifiedViewProps { lines: DiffLine[]; numWidth: number; language: Language | null; prismTheme: PrismTheme; } function linePrefix(type: DiffLine['type']) { if (type === 'added') return '+'; if (type === 'removed') return '-'; return ' '; } // Threshold above which we switch from a plain DOM table to a virtualized // list. Mirrors LogViewer — under this size the DOM stays debuggable; // above it tokenization + layout of thousands of rows starts to dominate // scroll. const VIRTUALIZE_THRESHOLD = 100; // Height of the scrolling viewport when virtualized. Kept here (not a prop) // because every existing consumer expects the viewer to expand to its // content; only the >100-line path needs a fixed window to virtualize. const VIRTUAL_VIEWPORT_HEIGHT = 480; interface RowProps { line: DiffLine; numWidth: number; language: Language | null; prismTheme: PrismTheme; } /** * One unified-diff row. CSS grid (not a table cell) so a `` * list can virtualize identical rows without a host `` (the * `display: table-row-group` virtual scrollers force on `` doesn't * play with arbitrary row heights). */ function Row({ line, numWidth, language, prismTheme }: RowProps) { const tone = DIFF_TONE_CLASSES[line.type]; const gutterCh = `calc(${numWidth}ch + 1rem)`; return (
{line.oldNumber ?? ''}
{line.newNumber ?? ''}
{linePrefix(line.type)}
); } /** * Single-column unified diff. Two gutters on the left carry the old / new * line numbers, the third (narrow) column is the +/-/space prefix, then * the content. Background tint per row signals the change kind. * * The gutter widths come from the globally-computed `numWidth` (passed * down from the viewer root). Using CSS grid with the same explicit * `gridTemplateColumns` on every row guarantees pixel-identical gutters * across all rows, even when content sizes vary. * * Diffs above {@link VIRTUALIZE_THRESHOLD} lines render through * `` so 1k–10k-line diffs don't lock the main thread. */ export function UnifiedView({ lines, numWidth, language, prismTheme, }: UnifiedViewProps) { if (lines.length > VIRTUALIZE_THRESHOLD) { return (
( )} increaseViewportBy={{ top: 200, bottom: 400 }} />
); } return (
{lines.map((line, i) => ( ))}
); }