Skip to content

fix(rtl): use logical spacing/text-align classes instead of physical ones - #749

Open
swe-sanad wants to merge 1 commit into
frappe:developfrom
SWE-Pioneers:fix/rtl-logical-properties
Open

fix(rtl): use logical spacing/text-align classes instead of physical ones#749
swe-sanad wants to merge 1 commit into
frappe:developfrom
SWE-Pioneers:fix/rtl-logical-properties

Conversation

@swe-sanad

Copy link
Copy Markdown

Problem

Hardcoded physical spacing/text-align classes (ml-/mr-, pl-/pr-, text-left/text-right) don't mirror when dir="rtl" is applied — margin/padding stays on the same physical side and text stays left/right-anchored regardless of direction.

Fix

Safe subset only: ml-/mr-ms-/me-, pl-/pr-ps-/pe-, text-left/righttext-start/end. Behavior-preserving for LTR (these resolve to the same physical side when direction is ltr) and correct under dir="rtl".

Deliberately does not touch left-/right- (positioning), border-l/r (side border width), or transforms (translate-x etc.) — those can sit right next to a converted class and interact with it in a way that needs a human to look, so a blind swap risks moving something to the wrong place.

How this was done

Converted mechanically with a small script that has its own 15+-case self-test (variant prefixes, negatives, arbitrary values, fractions all covered; verified px-/mx-/left-/right-/border-l-r/translate-x are never touched), then spot-checked by hand. Zero remaining ml-/mr-/pl-/pr-/text-left/text-right instances after conversion.

…ones

Safe subset only: ml-/mr- -> ms-/me-, pl-/pr- -> ps-/pe-, text-left/right ->
text-start/end. Behavior-preserving for LTR (these resolve to the same
physical side when direction is ltr) and correct under dir="rtl".

Deliberately does NOT touch left-/right- (positioning), border-l/r (side
border width), or transforms (translate-x etc.) -- those can sit right
next to a converted class and interact with it in a way that needs a
human to look, so a blind swap risks moving something to the wrong
place. Converted mechanically with a small script that has its own
15+-case self-test (ml/mr/pl/pr with variant prefixes, negatives,
arbitrary values, fractions; verified px-/mx-/left-/right-/border-l-r/
translate-x are never touched), then spot-checked by hand.
@greptile-apps

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 4/5

Fix the mixed physical/logical avatar margins before merging so the viewer stack mirrors correctly in RTL.

The broad utility conversion is supported, but ViewerAvatars still combines a physical base margin with a logical hover reset, producing inconsistent RTL spacing.

Files Needing Attention: frontend/src/components/ToolbarItems/ViewerAvatars.vue

Fix all with Greploop

Fix All in Claude Code Fix All in Codex

Reviews (1): Last reviewed commit: "fix(rtl): use logical spacing/text-align..." | Re-trigger Greptile

<div v-for="user in builderStore.viewers" :key="user.fullname">
<Tooltip :text="currentlyViewedByText" :hoverDelay="0.6" arrow-class="mb-3">
<div class="ml-[-10px] h-6 w-6 cursor-pointer transition-all group-hover:ml-0">
<div class="ml-[-10px] h-6 w-6 cursor-pointer transition-all group-hover:ms-0">

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Mixed avatar margin properties

When the viewer stack renders in RTL, the physical ml-[-10px] base margin does not pair with the logical group-hover:ms-0 reset, causing avatars to overlap or expand on inconsistent sides.

Suggested change
<div class="ml-[-10px] h-6 w-6 cursor-pointer transition-all group-hover:ms-0">
<div class="ms-[-10px] h-6 w-6 cursor-pointer transition-all group-hover:ms-0">

Fix in Claude Code Fix in Codex

@surajshetty3416

Copy link
Copy Markdown
Member

Automated review (Claude Code)

Overall this is a mechanical ml/mr/pl/pr/text-left → logical-property conversion, and most hunks are fine. The problems are all in spots where only half of a physical pair got converted, so LTR still looks right but RTL will be broken in a new way.

Actual bugs

  1. frontend/src/components/ToolbarItems/ViewerAvatars.vue:5 — base class stayed physical, hover went logical:

    class="ml-[-10px] ... group-hover:ms-0"
    

    In RTL ms-0 compiles to margin-right: 0, so it no longer cancels margin-left: -10px and the avatar-fan hover effect stops working entirely. Make both logical: -ms-[10px] ... group-hover:ms-0.

  2. frontend/src/components/BlockLayers.vue:35 — the row got pe-[2px], but the layer indentation is still an inline :style="{ paddingLeft: \${indent}px` }". In RTL the tree indents from the left while everything else mirrors. Should be paddingInlineStart`.

  3. frontend/src/components/Controls/Autocomplete.vue:59-ml-4-ms-4 on the overflow fade, but the gradient is still bg-gradient-to-r. Tailwind's to-r is not direction-aware, so in RTL the element sits on the opposite side while the fade still runs left→right, i.e. the opaque end lands over the text instead of at the edge.

border-l left behind next to a flipped ps-* — the divider and its padding end up on opposite sides in RTL. Use border-s:

  • Controls/CodeMirror/CustomSearchPanel.vue:49
  • Modals/TokenManager.vue:50-53
  • Settings/GlobalRedirects.vue:19 and cellDividerClass at line 140
  • ai/AITurnTimeline.vue:32
  • WebPagePresetPicker.vue:250

Same class of problem in WebPagePresetPicker.vue:94: the accent bar is absolute bottom-0 left-0 top-0 but the content padding became ps-3.

Padding flipped away from a physically-positioned sibling

  • Templates/TemplatePreview.vue:4pr-16pe-16, but the comment right above says this reserves room for the dialog's absolute close button at top-5/right-5, which is still physical. In RTL you get 4rem of padding on the left and the close button overlapping content on the right. Either keep pr-16 or flip the close button too; the comment is now stale either way.
  • PublishButton.vue:44pe-0 on a split button that still uses rounded-bl-none rounded-tl-none; in RTL the flat edge ends up on the wrong side of the seam. Should be rounded-s-none (or leave all three physical).
  • Controls/ColorInput.vue:21, Controls/FontInput.vue:6, ImageUploadInput.vue:19pl-8/pl-9ps-8/ps-9 reserves room for a swatch/icon that isn't in this diff. Worth confirming that adornment is positioned with start-*/inset-inline-start and not left-*, otherwise the gap opens on the wrong side.

One thing to verify globally: text-start only exists from Tailwind v3.3. ms-*/ps-* are older, so if the project is on <3.3 the text-lefttext-start swaps silently drop the alignment instead of failing loudly. Quick check of the pinned Tailwind version covers all ~12 of those hunks.

The remaining hunks (CommandPalette, LayersTab's p-3 pe-0, TemplateGallery's px-8 ... pe-5, DashboardSidebar, RouteTree*, Settings/*, VersionHistory, AI panels) look correct — the px-*/p-* shorthand plus ps/pe override ordering works out the same as the old pl/pr did.


This is an automated review and may be wrong — generated by a Claude Code devbox, not a human.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants