Skip to content

Added fixes to properly align paragraphs when loading RTL documents#2352

Open
claudiu-ior wants to merge 4 commits intosuperdoc-dev:mainfrom
claudiu-ior:rtl-initial-load-support
Open

Added fixes to properly align paragraphs when loading RTL documents#2352
claudiu-ior wants to merge 4 commits intosuperdoc-dev:mainfrom
claudiu-ior:rtl-initial-load-support

Conversation

@claudiu-ior
Copy link

Fix RTL (right-to-left) document rendering

Summary

  • Propagate the rightToLeft (bidi) paragraph property through pm-adapter into ParagraphAttrs so the layout engine and DomPainter know a paragraph is RTL
  • Make normalizeAlignment direction-aware: start/end now resolve to physical left/right based on paragraph direction instead of always mapping to LTR defaults
  • Add support for Arabic kashida justify variants (lowKashida, mediumKashida, highKashida) which were previously silently dropped
  • Update DomPainter to set dir="rtl" on RTL paragraph and line elements, default their text-align to right, and position segments from the right edge in segment-based rendering (lines with tabs and explicit X coordinates)

Problem

Opening an RTL Arabic document rendered all text left-aligned. Three independent issues contributed:

  1. RTL flag not propagated -- computeParagraphAttrs in pm-adapter read resolvedParagraphProperties.rightToLeft but never set direction or rtl on the output ParagraphAttrs, so DomPainter had no way to know a paragraph was RTL.

  2. Logical-to-physical alignment was not direction-aware -- normalizeAlignment always mapped start to left and end to right, which is wrong for RTL where start means right. Additionally, Arabic-specific OOXML justify values (lowKashida, mediumKashida, highKashida) were unrecognized and fell through to undefined.

  3. DomPainter assumed LTR -- No dir="rtl" attribute was set on elements. Justified text always used text-align: left as the base (incorrect for RTL, where the last line should right-align). Segment-based rendering (triggered by tabs or explicit positioning) always used style.left for X coordinates instead of style.right for RTL paragraphs.

Changes

File What changed
pm-adapter/src/attributes/paragraph.ts Derive isRtl from resolvedParagraphProperties.rightToLeft; pass it to normalizeAlignment; spread direction: 'rtl' and rtl: true onto output attrs
pm-adapter/src/attributes/spacing-indent.ts Add isRtl parameter to normalizeAlignment; flip start/end mapping for RTL; add lowKashida/mediumKashida/highKashida as justify aliases
painters/dom/src/renderer.ts Set dir="rtl" on paragraph and line elements; default RTL text-align to right; use right for justify base in RTL; introduce setHorizontalPos helper for segment-based rendering to use style.right instead of style.left for RTL
pm-adapter/src/attributes/spacing-indent.test.ts Tests for RTL start/end mapping and kashida variants
pm-adapter/src/index.test.ts Tests for RTL attr propagation, default alignment, explicit overrides, and start/end flipping

Test plan

  • Unit tests pass (pnpm test -- spacing-indent.test.ts and index.test.ts cover all new logic)
  • Load an RTL Arabic DOCX (e.g. intalio_template_17529.docx) -- text should be right-aligned with correct justification
  • Load an LTR document -- no regression, text still left-aligned as before
  • Verify mixed LTR/RTL documents render each paragraph with the correct direction
  • Check paragraphs with tabs in RTL documents -- segments should be positioned from the right edge

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 36824e438c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Copy link
Contributor

@caio-pizzol caio-pizzol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claudiu-ior nice work — alignment handling and the start/end flipping are well done and well tested.

one bug: the tab-stop positioning path sets style.right using values measured from the left edge, so RTL paragraphs with tabs will look wrong. left an inline comment with details.

one small cleanup suggestion on a repeated check.

tests: the alignment logic in pm-adapter is well covered. the renderer side (text-align branches, RTL positioning) could use a few tests — the existing createDomPainter setup in index.test.ts would work for that.

@claudiu-ior claudiu-ior requested a review from caio-pizzol March 11, 2026 10:30
Copy link
Contributor

@caio-pizzol caio-pizzol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claudiu-ior the style.right bug and text-align fixes look good.

heads up: indentation on RTL paragraphs will likely show on the wrong side. the renderer uses paddingLeft/paddingRight which don't flip when dir="rtl" is set, so the indent stays on the left when it should be on the right. there are already helpers for this in bidi.ts (mirrorIndentForRtl) that just need to be wired up — doesn't have to be in this PR, but good to know.

also, the RTL logic is now split across two places in renderer.ts. worth extracting into a feature module (features/rtl-paragraph/) following the pattern from #2324 — makes it easier to add the remaining pieces later.

left a couple inline comments.

@claudiu-ior claudiu-ior requested a review from caio-pizzol March 12, 2026 17:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants