Files
paseo/packages/app/src/git/diff-document/native-slabs.test.ts
T
Mohamed Boudra c7b103a2cd fix(app): stabilize canvas diff rendering
Keep diff headers and painted content on the same scroll clock while preserving native scrolling and independent per-file horizontal offsets.

Complete review, selection, typography, tree, and palette parity without returning line rendering to React.
2026-08-17 21:14:38 +02:00

82 lines
2.5 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { FILE_HEADER_HEIGHT } from "./model";
import {
buildNativeCanvasSlabs,
nativeCanvasSlabsForViewport,
nativeCanvasWindowBucket,
nativeCanvasWindowTop,
nativeStickyHeaderIndices,
} from "./native-slabs";
import type { DiffDocumentModel } from "./types";
function modelWithBodies(
bodies: Array<{ path: string; bodyTop: number; bottom: number }>,
): DiffDocumentModel {
return {
files: bodies.map((body, fileIndex) => ({
file: {} as never,
fileIndex,
path: body.path,
top: body.bodyTop - FILE_HEADER_HEIGHT,
headerHeight: FILE_HEADER_HEIGHT,
bodyTop: body.bodyTop,
bodyHeight: body.bottom - body.bodyTop,
bottom: body.bottom,
gutterWidth: 48,
contentWidth: 500,
rowStart: 0,
rowEnd: 0,
isCollapsed: body.bottom === body.bodyTop,
})),
rows: [],
height: bodies.at(-1)?.bottom ?? 0,
lineHeight: 20,
layout: "unified",
wrapLines: false,
viewportWidth: 400,
};
}
describe("native canvas slabs", () => {
it("identifies each direct file header child for native sticky scrolling", () => {
expect(nativeStickyHeaderIndices(0)).toEqual([]);
expect(nativeStickyHeaderIndices(3)).toEqual([1, 3, 5]);
});
it("cuts large file bodies into fixed document-positioned slabs", () => {
const slabs = buildNativeCanvasSlabs(
modelWithBodies([
{ path: "small.ts", bodyTop: FILE_HEADER_HEIGHT, bottom: FILE_HEADER_HEIGHT + 200 },
{
path: "large.ts",
bodyTop: FILE_HEADER_HEIGHT * 2 + 200,
bottom: FILE_HEADER_HEIGHT * 2 + 3400,
},
]),
600,
);
expect(slabs.map(({ path, top, height }) => ({ path, top, height }))).toEqual([
{ path: "small.ts", top: 30, height: 200 },
{ path: "large.ts", top: 260, height: 1200 },
{ path: "large.ts", top: 1460, height: 1200 },
{ path: "large.ts", top: 2660, height: 800 },
]);
});
it("retains only viewport-adjacent slabs and updates on half-viewport boundaries", () => {
const slabs = buildNativeCanvasSlabs(
modelWithBodies([
{ path: "large.ts", bodyTop: FILE_HEADER_HEIGHT, bottom: FILE_HEADER_HEIGHT + 4800 },
]),
600,
);
expect(nativeCanvasSlabsForViewport(slabs, 1700, 600).map((slab) => slab.top)).toEqual([
30, 1230, 2430,
]);
expect(nativeCanvasWindowBucket(899, 600)).toBe(2);
expect(nativeCanvasWindowTop(2, 600)).toBe(600);
});
});