mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-06 16:34:36 +00:00
feat(app): make Explorer a first-class pane host (#3826)
This commit is contained in:
@@ -8,12 +8,7 @@ import { DocumentFileHeader } from "./document-file-header";
|
||||
import { hitTestDiffDocument, selectedSourceText } from "./hit-testing";
|
||||
import { retainHorizontalOffsetMapForPaths } from "./horizontal-offsets";
|
||||
import { HorizontalScroll } from "./horizontal-scroll.web";
|
||||
import {
|
||||
buildDiffDocumentModel,
|
||||
FILE_HEADER_HEIGHT,
|
||||
resolveRelayoutScrollTop,
|
||||
retainReusableModels,
|
||||
} from "./model";
|
||||
import { buildDiffDocumentModel, FILE_HEADER_HEIGHT, resolveRelayoutScrollTop } from "./model";
|
||||
import { paintWebViewport } from "./paint.web";
|
||||
import { hasPointerDragStarted } from "./pointer-gesture";
|
||||
import { createMeasuredAdvances } from "./text-measurement";
|
||||
@@ -25,22 +20,20 @@ import type {
|
||||
DiffTypography,
|
||||
TextMeasurer,
|
||||
} from "./types";
|
||||
import { useDiffDocumentWorkspaceCache } from "./workspace-cache";
|
||||
|
||||
const DEFAULT_MONO_STACK = "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace";
|
||||
const RESIZE_SETTLE_DELAY_MS = 120;
|
||||
|
||||
export function DiffSurface(props: DiffSurfaceProps) {
|
||||
const { t } = useTranslation();
|
||||
const workspaceCache = useDiffDocumentWorkspaceCache();
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const canvasScratchRef = useRef<HTMLCanvasElement>(null);
|
||||
const scrollRef = useRef<HTMLDivElement>(null);
|
||||
const modelRef = useRef<ReturnType<typeof buildDiffDocumentModel> | null>(null);
|
||||
const previousModelRef = useRef<ReturnType<typeof buildDiffDocumentModel> | null>(null);
|
||||
const reusableModelRef = useRef<{
|
||||
dependencies: readonly unknown[];
|
||||
models: ReturnType<typeof buildDiffDocumentModel>[];
|
||||
} | null>(null);
|
||||
const consumedFocusRef = useRef<string | null>(null);
|
||||
const scrollTopRef = useRef(0);
|
||||
const horizontalOffsetsRef = useRef(new Map<string, number>());
|
||||
@@ -60,7 +53,6 @@ export function DiffSurface(props: DiffSurfaceProps) {
|
||||
const forcePaintRef = useRef(true);
|
||||
const canvasWindowRef = useRef({ top: 0, height: 0 });
|
||||
const [viewport, setViewport] = useState({ width: 0, height: 0 });
|
||||
const [loadedTypography, setLoadedTypography] = useState<DiffTypography | null>(null);
|
||||
const [hoveredAffordance, setHoveredAffordance] = useState<{
|
||||
hit: Extract<DiffHit, { kind: "cell" }>;
|
||||
left: number;
|
||||
@@ -81,10 +73,28 @@ export function DiffSurface(props: DiffSurfaceProps) {
|
||||
}),
|
||||
[family, props.displayPreferences.codeFontSize],
|
||||
);
|
||||
const measurement = useMemo(
|
||||
() => (loadedTypography ? createWebTextMeasurer(loadedTypography) : null),
|
||||
[loadedTypography],
|
||||
const typographyResource = useMemo(
|
||||
() =>
|
||||
workspaceCache.typography({
|
||||
typography: desiredTypography,
|
||||
load: async () => {
|
||||
await Promise.all([
|
||||
document.fonts.load(`400 ${desiredTypography.size}px ${desiredTypography.family}`),
|
||||
document.fonts.load(`600 ${desiredTypography.size}px ${desiredTypography.family}`),
|
||||
]);
|
||||
await document.fonts.ready;
|
||||
},
|
||||
createMeasurer: () => createWebTextMeasurer(desiredTypography),
|
||||
}),
|
||||
[desiredTypography, workspaceCache],
|
||||
);
|
||||
const [readyTypographyResource, setReadyTypographyResource] = useState<ReturnType<
|
||||
typeof workspaceCache.typography
|
||||
> | null>(() => (typographyResource.isReady() ? typographyResource : null));
|
||||
const loadedTypography =
|
||||
readyTypographyResource === typographyResource ? typographyResource.typography : null;
|
||||
const measurement =
|
||||
readyTypographyResource === typographyResource ? typographyResource.measureText : null;
|
||||
const reviewActions = props.mode.kind === "working" ? props.mode.reviewActions : undefined;
|
||||
const model = useMemo(() => {
|
||||
if (!loadedTypography || !measurement) {
|
||||
@@ -95,22 +105,7 @@ export function DiffSurface(props: DiffSurfaceProps) {
|
||||
lineHeight: desiredTypography.lineHeight,
|
||||
});
|
||||
}
|
||||
const dependencies = [
|
||||
props.files,
|
||||
props.displayPreferences.layout,
|
||||
props.displayPreferences.wrapLines,
|
||||
viewport.width,
|
||||
loadedTypography,
|
||||
measurement,
|
||||
props.palette,
|
||||
t,
|
||||
] as const;
|
||||
const previous = reusableModelRef.current;
|
||||
const canReuse = previous?.dependencies.every(
|
||||
(dependency, index) => dependency === dependencies[index],
|
||||
);
|
||||
const reuseFrom = canReuse ? previous?.models : undefined;
|
||||
const next = buildDiffDocumentModel({
|
||||
return workspaceCache.buildModel({
|
||||
files: props.files,
|
||||
collapsedFilePaths: props.collapsedFilePaths,
|
||||
layout: props.displayPreferences.layout,
|
||||
@@ -124,13 +119,7 @@ export function DiffSurface(props: DiffSurfaceProps) {
|
||||
binary: t("workspace.git.diff.binaryFile"),
|
||||
tooLarge: t("workspace.git.diff.tooLarge"),
|
||||
},
|
||||
reuseFrom,
|
||||
});
|
||||
reusableModelRef.current = {
|
||||
dependencies,
|
||||
models: retainReusableModels(reuseFrom, next),
|
||||
};
|
||||
return next;
|
||||
}, [
|
||||
measurement,
|
||||
props.collapsedFilePaths,
|
||||
@@ -143,6 +132,7 @@ export function DiffSurface(props: DiffSurfaceProps) {
|
||||
desiredTypography.lineHeight,
|
||||
loadedTypography,
|
||||
viewport.width,
|
||||
workspaceCache,
|
||||
]);
|
||||
modelRef.current = model;
|
||||
|
||||
@@ -280,18 +270,19 @@ export function DiffSurface(props: DiffSurfaceProps) {
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
void (async () => {
|
||||
await Promise.all([
|
||||
document.fonts.load(`400 ${desiredTypography.size}px ${desiredTypography.family}`),
|
||||
document.fonts.load(`600 ${desiredTypography.size}px ${desiredTypography.family}`),
|
||||
]);
|
||||
await document.fonts.ready;
|
||||
if (!cancelled) setLoadedTypography(desiredTypography);
|
||||
})();
|
||||
if (typographyResource.isReady()) {
|
||||
setReadyTypographyResource(typographyResource);
|
||||
return;
|
||||
}
|
||||
setReadyTypographyResource(null);
|
||||
void typographyResource.load().then(() => {
|
||||
if (!cancelled) setReadyTypographyResource(typographyResource);
|
||||
return undefined;
|
||||
});
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [desiredTypography]);
|
||||
}, [typographyResource]);
|
||||
useLayoutEffect(() => {
|
||||
const previous = previousModelRef.current;
|
||||
const scroll = scrollRef.current;
|
||||
|
||||
Reference in New Issue
Block a user