feat(layout): opt-in RTL layout mirroring#50
Open
chiefcll wants to merge 1 commit into
Open
Conversation
Introduce an inherited `rtl` flag on nodes that mirrors child x-positions within the parent's width and reverses `left`/`right` text alignment. The flag resolves by inheritance (own override, else parent), propagated via a new `UpdateType.Direction` pass; the mirror is applied as a temporary shift/restore of the local transform in the world-transform step, so LTR apps pay only a single boolean check on the hot path. This covers RTL layout structure only (rails/nav mirroring, alignment). Bidirectional text reordering (Hebrew/Arabic glyph order) is a separate opt-in follow-up and is intentionally out of scope here. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 tasks
elsassph
reviewed
Jun 1, 2026
| } | ||
| } | ||
|
|
||
| if (rtlMirrored === true) { |
There was a problem hiding this comment.
Maybe could have gone with if (rtlOrigTx !== 0) and drop the bool
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an inherited, opt-in
rtlflag to nodes that mirrors layout horizontally — childxis measured from the parent's right edge, andleft/righttext alignment is reversed. Settingrtlon the root mirrors the whole app; an explicitrtl: falseopts a sub-tree back out.Scope: this is RTL layout structure only (rails/nav mirroring, alignment). Bidirectional text reordering (Hebrew/Arabic glyph order) is a separate opt-in follow-up (Phase 2) and is intentionally out of scope here. Until that lands,
rtlshould be documented as "layout mirroring", not full RTL.How it works
rtl: boolean | nullprop (null= inherit, the default), exposed viaINodeProps/INode._ownRtl(local override) + resolved_rtlonCoreNode; inheritance resolves top-down through a newUpdateType.Directionpass that reuses the existing dirty-flag traversal. The root is resolved eagerly in its setter (it's driven byStage.drawFrame, notupdate()).lt.tx += parentW − 2·x − w·scaleX) is applied as a temporary shift/restore of the local transform during the world-transform compose, so the cached transform stays pristine and isn't double-mirrored next frame.parent._rtl === truecheck per node; no bundle weight worth gating.textAlignleft/rightflips via a sharedresolveTextAlign()used by both Canvas and SDF renderers and text-node containment; SDF layout cache key now includesrtl. Text nodes resolve direction before generating layout, so a change reflows in the same frame (no flash).Caveat
Mirroring requires a known parent width (
w). A parent withoutwlays out LTR (matches the upstream Lightning behavior).Test plan
CoreNode.test.ts): inheritance, explicit override, mirror math,scaleX, LTR/zero-width no-mirror cases, local-transform restoration.tsc --buildclean; Prettier clean.examples/tests/rtl-layout.tswith a CI-certified snapshot generated via Docker. Visually verified: positions mirror under an RTL parent, child markers mirror by each box's own resolvedrtl, thertl: falseoverride works, and RTL text right-aligns.🤖 Generated with Claude Code