Skip to content

Columns ignore the section's w:bidi: the first column renders on the left in RTL documents #3952

Description

@Nathaniel-260

What happens

In a section that carries w:sectPr/w:bidi, columns fill left to right. The first paragraph of a two-column Hebrew section lands in the left column and overflow spills into the right one.

Word does the opposite: in an RTL section the first column is the rightmost.

Why it is more than a cosmetic flip

Selection follows the fill order, so the mirrored layout breaks dragging in a way that looks like a selection bug:

  1. Press inside the column a Hebrew reader starts from — the right one.
  2. Drag down a few lines. So far so good.
  3. Keep dragging into the left column.

Everything already highlighted below the anchor disappears, and the left column lights up instead. Measured on a 44-paragraph document: 8 highlighted lines in the right column drop to 5 the moment the pointer crosses the gutter. The engine is faithful to the order it built; the order is what is mirrored.

Two more consequences fall out of the same axis:

  • A point inside the right column but below its last line is not clamped to that column — the head lands in the left column at the same y.
  • Shift+ArrowDown does not cross the column boundary at all: from a verified caret on line 23 it ends up selecting 04–23, i.e. the head jumped above the anchor to the top of the first column.

So there is no keyboard workaround either. Selecting inside a single column works, and Ctrl+A works.

Reproduction

Any Hebrew document with two columns. Minimal path:

  1. New document, section with <w:bidi/> (Word writes this for a Hebrew document).
  2. Layout → Columns → Two.
  3. Type or paste enough text to overflow into the second column.
  4. Observe that paragraph 1 is on the left.

The exported .docx is correct throughout — <w:cols w:num="2" w:equalWidth="1"/> and <w:bidi/> both round-trip, and the file opens correctly in Word. The damage is in rendering and interaction only.

Where it comes from

SectionDirectionContext in packages/layout-engine/contracts/src/direction-context.ts already documents pageDirection (from w:sectPr/w:bidi) as governing "section-level chrome only (page numbers, columns, gutters)". But ColumnGeometry measures x "from the content-area left edge", and no function in the column geometry takes a direction. The axis is documented and never consumed.

A control run confirms it: the same document in English, with no w:bidi at all, produces byte-identical geometry — so direction is not read on the column axis in either case.

Environment

superdoc@2.10.0 (@superdoc/docx-engine@0.9.0). Also checked 2.11.0-next.9: layout-engine/contracts/src/column-layout.d.ts is byte-identical there, and no column-geometry signature takes a direction, so this is still open on next.

I have a fix for the geometry side and will open a PR referencing this issue.

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions