/* eslint-disable @typescript-eslint/ban-ts-comment */ import { getSplitContentLines, type DiffFile } from "@git-diff-view/core"; import { removeAllSelection, syncScroll, diffFontSizeName, borderColorName, diffAsideWidthName, getDiffIdFromElement, } from "@git-diff-view/utils"; import { Fragment, memo, useEffect, useRef } from "react"; import * as React from "react"; // @ts-ignore import { useSyncExternalStore } from "use-sync-external-store/shim/index.js"; import { useTextWidth } from "../hooks/useTextWidth"; import { DiffSplitContentLine } from "./DiffSplitContentLineNormal"; import { DiffSplitExtendLine } from "./DiffSplitExtendLineNormal"; import { DiffSplitHunkLine } from "./DiffSplitHunkLineNormal"; import { DiffSplitWidgetLine } from "./DiffSplitWidgetLineNormal"; import { SplitSide } from "./DiffView"; import { useDiffViewContext } from "./DiffViewContext"; import type { MouseEventHandler } from "react"; const DiffSplitViewTable = ({ side, diffFile, enableAddWidget, enableHighlight, onMouseDown, }: { side: SplitSide; diffFile: DiffFile; enableHighlight: boolean; enableAddWidget: boolean; onMouseDown?: MouseEventHandler; }) => { const className = side === SplitSide.new ? "new-diff-table" : "old-diff-table"; const lines = getSplitContentLines(diffFile); return ( {lines.map((line) => ( ))}
{SplitSide[side]} line number {SplitSide[side]} line content
); }; export const DiffSplitViewNormal = memo(({ diffFile }: { diffFile: DiffFile }) => { const ref1 = useRef(null); const ref2 = useRef(null); const ref = useRef(null); const tempRef = useRef(undefined); const splitLineLength = Math.max(diffFile.splitLineLength, diffFile.fileLineLength); const { useDiffContext } = useDiffViewContext(); const { fontSize, enableAddWidget, enableHighlight } = useDiffContext.useShallowStableSelector((s) => ({ fontSize: s.fontSize, enableAddWidget: s.enableAddWidget, enableHighlight: s.enableHighlight, })); useSyncExternalStore(diffFile.subscribe, diffFile.getUpdateCount, diffFile.getUpdateCount); useEffect(() => { const left = ref1.current; const right = ref2.current; if (!left || !right) return; return syncScroll(left, right); }, []); const font = React.useMemo( () => ({ fontSize: fontSize + "px", fontFamily: "Menlo, Consolas, monospace" }), [fontSize] ); const _width = useTextWidth({ text: splitLineLength.toString(), font, }); const width = Math.max(40, _width + 25); const setStyle = (side?: SplitSide) => { if (!ref.current) return; if (!side) { ref.current.textContent = ""; } else { const id = `diff-root${diffFile.getId()}`; ref.current.textContent = `#${id} [data-state="extend"] {user-select: none} \n#${id} [data-state="hunk"] {user-select: none} \n#${id} [data-state="widget"] {user-select: none}`; } }; const onMouseDown: MouseEventHandler = (e) => { let ele: Element | null = e.target as Element; // need remove all the selection if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") { removeAllSelection(); return; } const id = getDiffIdFromElement(ele as HTMLElement); if (id && id !== `diff-root${diffFile.getId()}`) { return; } while (ele && ele instanceof HTMLElement) { const state = ele.getAttribute("data-state"); const side = ele.getAttribute("data-side") as unknown as SplitSide; if (side) { if (tempRef.current !== (SplitSide[side] as unknown as SplitSide)) { tempRef.current = SplitSide[side] as unknown as SplitSide; setStyle(SplitSide[side] as unknown as SplitSide); removeAllSelection(); } } if (state) { if (state === "extend" || state === "hunk" || state === "widget") { if (tempRef.current !== undefined) { tempRef.current = undefined; setStyle(undefined); removeAllSelection(); } return; } else { return; } } ele = ele.parentElement; } }; return (