Skip to content

[bug]: Patch preview stacks side-by-side panes vertically and renders excessive line spacing (3.1.1) #304

Description

@yanchxx

Affected area

File rendering or format fidelity — Patch comparison in @file-viewer/renderer-text.

Summary

In File Viewer 3.1.1, a .patch preview reports side-by-side, but the old/new panes are stacked vertically. Ordinary one-line code rows are approximately 84px high because whitespace from the generated HTML template is rendered as extra lines.

This is reproducible in a production build and in an isolated browser page using the same installed renderer, without application CSS, React, Tailwind, or the Vite runtime. It occurs with and without Shadow DOM.

File type and extension

Unified Git diff: .patch.

Package names and exact versions

  • @file-viewer/react-full: 3.1.1
  • @file-viewer/preset-all: 3.1.1
  • @file-viewer/core: 3.1.1
  • @file-viewer/renderer-text: 3.1.1
  • @file-viewer/capability-text-tools: 3.1.1
  • diff2html: 3.4.56
  • @file-viewer/vite-plugin: 3.1.1

Sample sharing method

Public reproduction file linked below, plus a complete small synthetic patch inline. No private files or customer data are involved.

Sample or reproduction artifact

The repository's own version-pinned demo sample reproduces the issue when loaded into the installed 3.1.1 renderer:

https://github.com/flyfish-dev/file-viewer/blob/v3.1.1/apps/viewer-demo/public/example/change.patch

The following smaller synthetic change.patch also reproduces it; preserve a trailing newline:

diff --git a/config.ts b/config.ts
index 83db48f..bf43abc 100644
--- a/config.ts
+++ b/config.ts
@@ -1,4 +1,5 @@
 export const preview = {
-  mode: "standard",
+  mode: "full",
   locale: "zh-CN",
+  toolbar: false,
 };

Minimal reproduction steps

  1. In a React + Vite application, install @file-viewer/react-full@3.1.1 and @file-viewer/vite-plugin@3.1.1. The resolved diff2html version in this reproduction is 3.4.56.

  2. Use the documented fileViewerRenderers({ copyAssets: true }) Vite plugin and render the synthetic sample above with:

    import { FileViewer } from '@file-viewer/react-full';
    import patchSource from './change.patch?raw';
    
    const buffer = new TextEncoder().encode(patchSource).buffer;
    const options = {
      styleIsolation: 'shadow',
      theme: 'light',
      toolbar: false,
    };
    
    export default function App() {
      return (
        <div style={{ width: 1234, height: 900 }}>
          <FileViewer
            name="change.patch"
            type="patch"
            buffer={buffer}
            options={options}
          />
        </div>
      );
    }
  3. Open the page and inspect the patch comparison. The issue is also present when serving the production output (vite build followed by vite preview).

  4. Observe vertically stacked old/new panes and oversized rows. Switching to styleIsolation: 'none' does not resolve the underlying layout problem.

The public demo URL above is a fixture source, not a claim that the currently deployed online demo was tested. The fixture was tested against the installed 3.1.1 renderer in an isolated local browser page.

Actual behavior and isolation evidence

Measured in Chromium, with a 1234px-wide container and the synthetic sample:

Variant Old/new panes Ordinary code-row height
Production application Stacked vertically ~84px
Same page after removing application-injected styles Stacked vertically ~84px
Standalone File Viewer Patch renderer, plain DOM Stacked vertically ~84px
Standalone File Viewer Patch renderer, Shadow DOM Stacked vertically ~84px
Raw diff2html HTML + its bundled CSS Side by side ~18px
Same raw HTML after File Viewer's rich-HTML sanitizer + bundled CSS Side by side ~18px
File Viewer renderer + bundled diff2html CSS Side by side ~105px

The upstream change.patch fixture also produced stacked panes and ~84px code rows in the standalone renderer. This rules out the synthetic input and the application stylesheet as the sole cause.

Likely source-level causes

The patchStyle string in the installed package matches the version-tagged source exactly:

https://github.com/flyfish-dev/file-viewer/blob/v3.1.1/packages/renderers/text/src/patch.ts#L13-L38

  1. The injected stylesheet styles file headers, tables, line numbers, and colors, but does not define the side-by-side layout for .d2h-files-diff / .d2h-file-side-diff. The text-tools capability registers diff2html.html but does not import its stylesheet:

    https://github.com/flyfish-dev/file-viewer/blob/v3.1.1/packages/capabilities/text-tools/src/index.ts

  2. The following rule preserves whitespace on the outer generated line wrapper:

    .patch-body .d2h-code-side-line,
    .patch-body .d2h-code-line {
      padding: 0 10px;
      white-space: pre-wrap;
      word-break: break-word;
    }

    diff2html emits indentation/newlines around its prefix/content spans:

    <div class="d2h-code-side-line">
        <span class="d2h-code-line-prefix">-</span>
        <span class="d2h-code-line-ctn">  mode: "standard",</span>
    </div>

    Those template text nodes become extra rendered lines. Whitespace preservation should apply to the actual code content without preserving the surrounding template formatting.

    Importing diff2html CSS alone is insufficient: File Viewer's more-specific .patch-body .d2h-code-side-line rule still wins over the upstream whitespace rule. In the measured isolated case, it restored columns but increased the row height to ~105px.

For diagnostic confirmation only, adding two groups of local rules — side-by-side layout and whitespace scoping — restored two columns and reduced rows to ~23px. This was not shipped as a fix, and is not intended as a complete proposed stylesheet; long lines, empty placeholders, change alignment, zoom, and themes still need proper regression coverage.

Expected behavior

  • Old/new content appears in adjacent panes when the renderer reports side-by-side.
  • A short single-line source line occupies one visual line, preserving source indentation but not HTML template whitespace.
  • Context lines, inserted/deleted lines, and empty alignment placeholders remain aligned across panes.
  • Behavior is correct on a clean page and under Shadow DOM, without relying on host-global CSS.

Environment

  • macOS; Chromium via the project's Playwright-managed headless browser.
  • React 19.2.8; Vite 8.2.2.
  • Reproduced in the application's production build and a separate bundled standalone-renderer browser harness.
  • Root deployment path; local/self-hosted assets. The standalone case needs no external renderer assets.
  • No application stylesheet in the standalone case. No special CSP was added there.

Regression status

Unknown. Earlier File Viewer versions were not tested.

Console and network evidence

No runtime JavaScript exception was observed in the production reproduction. Patch parsing completes and the expected text appears; this is a layout/whitespace problem, not a failed asset request.

Required confirmations

  • I searched existing issues and did not find the same reproduction.
  • I provided a public sample link and a complete small synthetic patch.
  • Screenshots are not being used as a substitute for a real sample or reproduction.
  • The inline sample is synthetic and safe to redistribute for regression testing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status:needs-sampleA source or reduced reproduction file is required

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions