Skip to content

feat(admin): add full RTL support to admin UI#565

Merged
ascorbic merged 22 commits intoemdash-cms:mainfrom
ophirbucai:feat/i18n-dir-support-classes
Apr 15, 2026
Merged

feat(admin): add full RTL support to admin UI#565
ascorbic merged 22 commits intoemdash-cms:mainfrom
ophirbucai:feat/i18n-dir-support-classes

Conversation

@ophirbucai
Copy link
Copy Markdown
Contributor

@ophirbucai ophirbucai commented Apr 14, 2026

What does this PR do?

Adds full RTL (right-to-left) support to the admin UI by converting all directional Tailwind classes to their direction-aware equivalents. The admin interface now automatically mirrors its layout for RTL languages like Arabic, Hebrew, Persian (Farsi), Urdu, Kurdish, and Pashto.

  • Replaced 177+ occurrences of non-direction-aware classes (text-left/right, ml-/mr-, pl-/pr-, left-/right-, border-l/r) with logical properties (text-start/end, ms-/me-, ps-/pe-, start-/end-, border-s/e)
  • Added targeted RTL overrides for Kumo Sidebar components using Tailwind's [&>span] selector syntax and rtl: variant
  • All 48+ admin component files now support automatic RTL layout mirroring

Closes #

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

AI-generated code disclosure

  • This PR includes AI-generated code

Screenshots / test output

Verified pnpm typecheck and pnpm --silent lint:json | jq '.diagnostics | length' clean across all modified files. Manual testing confirms RTL layout mirroring works correctly in admin UI when locale direction is set to RTL.

ophirbucai and others added 16 commits April 14, 2026 04:51
Analysis of messages.po~
The backup file is outdated:
- messages.po: 5,519 lines (159KB) - current, fully extracted
- messages.po~: 749 lines (19KB) - old backup, incomplete

Key differences:
- The ~ file has only 749 lines vs 5,519 in the current file
- The ~ file is dated Apr 14 04:14 (same timestamp, so created during the same operation)
Introduces LocaleDirectionProvider component that manages text direction
and language attributes for RTL locales like Arabic.

Implementation:
- LocaleDirectionProvider wraps Kumo's DirectionProvider
- Syncs document.documentElement.dir and lang attributes with current locale
- Integrates with useLocale hook for locale state
- Properly ordered: I18nProvider → LocaleDirectionProvider

Features:
- Automatic direction switching (LTR ↔ RTL) on locale change
- Single source of truth for locale → direction mapping
- Updates both HTML lang and dir attributes (WCAG compliance)
- Comprehensive test coverage with cleanup hooks

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace non-direction-aware Tailwind classes with direction-aware equivalents
in editor components to support RTL layouts:

- pl-* → ps-* (padding inline start)
- ml-* → ms-* (margin inline start)
- mr-* → me-* (margin inline end)
- left-* → start-* (positioning - CSS only, not FloatingUI placement)
- right-* → end-* (positioning - CSS only)
- text-left → text-start (text alignment)
- border-l → border-s (border inline start)

Note: FloatingUI placement values (e.g., "left-start") remain unchanged
as they are library-specific enums, not directional CSS classes.

Files updated:
- ContentEditor.tsx (5 changes)
- PortableTextEditor.tsx (3 changes)
- RepeaterField.tsx (1 change)
- editor/DocumentOutline.tsx (5 changes)
- editor/BlockMenu.tsx (6 changes)
- editor/ImageNode.tsx (2 changes)
- editor/ImageDetailPanel.tsx (1 change)
- editor/PluginBlockNode.tsx (1 change)
- editor/DragHandleWrapper.tsx (no CSS changes - FloatingUI placement kept as-is)
Replace non-direction-aware Tailwind classes with direction-aware equivalents
in media management components to support RTL layouts:

- left-* → start-* (positioning)
- right-* → end-* (positioning)
- pl-* → ps-* (padding inline start)
- pr-* → pe-* (padding inline end)
- ml-* → ms-* (margin inline start)
- text-left → text-start (text alignment)
- text-right → text-end (text alignment)
- border-l → border-s (border inline start)

Files updated:
- MediaLibrary.tsx (11 changes)
- MediaPickerModal.tsx (8 changes)
- MediaDetailPanel.tsx (2 changes)
Replace non-direction-aware Tailwind classes with direction-aware equivalents
in content list and picker components to support RTL layouts:

- left-* → start-* (positioning)
- right-* → end-* (positioning)
- pl-* → ps-* (padding inline start)
- mr-* → me-* (margin inline end)
- text-left → text-start (text alignment)
- text-right → text-end (text alignment)

Files updated:
- ContentList.tsx (13 changes)
- ContentPickerModal.tsx (4 changes)
Replace non-direction-aware Tailwind classes with direction-aware equivalents
in user and comment management components to support RTL layouts:

- left-* → start-* (positioning)
- right-* → end-* (positioning)
- pl-* → ps-* (padding inline start)
- ml-* → ms-* (margin inline start)
- text-left → text-start (text alignment)
- text-right → text-end (text alignment)
- border-l → border-s (border inline start)

Files updated:
- users/UserList.tsx (7 changes)
- users/UserDetail.tsx (2 changes)
- users/InviteUserModal.tsx (1 change)
- comments/CommentInbox.tsx (11 changes)
- comments/CommentDetail.tsx (1 change)
Replace non-direction-aware Tailwind classes with direction-aware equivalents
in plugin and marketplace components to support RTL layouts:

- left-* → start-* (positioning)
- right-* → end-* (positioning)
- pl-* → ps-* (padding inline start)

Files updated:
- MarketplaceBrowse.tsx (2 changes)
- ThemeMarketplaceBrowse.tsx (2 changes)
- MarketplacePluginDetail.tsx (4 changes)
- ThemeMarketplaceDetail.tsx (4 changes)
- SandboxedPluginPage.tsx (1 change)
Complete refactoring to direction-aware Tailwind classes across remaining
admin components to support RTL layouts.

Replaced non-direction-aware classes with direction-aware equivalents:
- text-left/right → text-start/end
- pl-*/pr-* → ps-*/pe-*
- ml-*/mr-* → ms-*/me-*
- left-*/right-* → start-*/end-*
- border-l/r → border-s/e
- border-l-*/r-* → border-s-*/e-*

Phase 6 - Schema & Content Types (3 files):
- ContentTypeList.tsx
- ContentTypeEditor.tsx
- FieldEditor.tsx

Phase 7 - Taxonomy, Menus, Sections & Widgets (8 files):
- TaxonomyManager.tsx
- TaxonomySidebar.tsx
- MenuEditor.tsx
- MenuList.tsx
- Sections.tsx
- SectionPickerModal.tsx
- Widgets.tsx
- Redirects.tsx

Phase 8 - Import, Core UI & Miscellaneous (8 files):
- WordPressImport.tsx
- Header.tsx
- Sidebar.tsx
- RevisionHistory.tsx
- SeoImageField.tsx
- WelcomeModal.tsx
- settings/AllowedDomainsSettings.tsx
- routes/bylines.tsx

All 177 occurrences across 48 files refactored.
Convert remaining ml-/mr- icon spacing classes to direction-aware ms-/me-:
- MarketplaceBrowse.tsx
- LoginPage.tsx
- ThemeMarketplaceDetail.tsx
- SetupWizard.tsx
- ThemeMarketplaceBrowse.tsx
- CapabilityConsentDialog.tsx
- PluginManager.tsx
- users/RoleBadge.tsx
- MarketplacePluginDetail.tsx

These were missed in the initial batch refactor as they were primarily
used for icon spacing within buttons and labels.
Update @cloudflare/kumo from 1.16.0/1.10.0 to 1.18.0 across admin
and blocks packages using pnpm catalog for consistent versioning.

Changes:
- Add @cloudflare/kumo: ^1.18.0 to pnpm-workspace catalog
- Update packages/admin to use catalog: (from ^1.16.0)
- Update packages/blocks to use catalog: (from ^1.10.0)

This update brings the latest Kumo UI components and potential
RTL improvements. Custom CSS overrides in admin/src/styles.css
remain in place for Kumo Sidebar RTL support.
Add className="[&>span]:text-start" to all KumoSidebar.GroupLabel
components to override Kumo library's hard-coded text-left class.

Kumo v1.18.0 still uses non-RTL-aware classes in GroupLabel. This
scoped override using Tailwind's selector syntax ensures group labels
align correctly in both LTR and RTL layouts.

Affected labels: Content, Manage, Admin, Plugins
Add RTL-aware classes to Header component:
- Sidebar.Trigger: Add rtl:rotate-180 to flip hamburger icon in RTL
- ArrowSquareOut icon: Use me-1 (margin-inline-end) instead of mr-1
- Logout button: Use text-start instead of text-left for alignment

All changes use Tailwind v4's logical properties and rtl: variant
for automatic RTL layout support.
Copilot AI review requested due to automatic review settings April 14, 2026 21:13
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 14, 2026

🦋 Changeset detected

Latest commit: a1b9f0b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@emdash-cms/admin Minor
emdash Minor
@emdash-cms/cloudflare Minor
@emdash-cms/auth Minor
@emdash-cms/blocks Minor
@emdash-cms/gutenberg-to-portable-text Minor
@emdash-cms/x402 Minor
create-emdash Minor
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions
Copy link
Copy Markdown
Contributor

Scope check

This PR touches 52 files. PRs with a broad scope are harder to review. Please confirm the scope hasn't drifted beyond the intended change.

If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs.

See CONTRIBUTING.md for contribution guidelines.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Apr 14, 2026

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@565

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@565

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@565

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@565

emdash

npm i https://pkg.pr.new/emdash@565

create-emdash

npm i https://pkg.pr.new/create-emdash@565

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@565

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@565

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@565

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@565

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@565

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@565

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@565

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@565

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@565

commit: a1b9f0b

Update test selectors from `button.text-left` to `button.text-start`
to match the RTL refactoring. The widget expand buttons now use
direction-aware classes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds RTL (right-to-left) layout mirroring support across the admin UI by converting direction-specific Tailwind utilities to logical (direction-aware) equivalents, and aligns @cloudflare/kumo versions via pnpm catalogs.

Changes:

  • Replace LTR-specific Tailwind utilities (left/right, ml/mr, pl/pr, text-left/right, border-l/r, etc.) with logical equivalents (start/end, ms/me, ps/pe, text-start/end, border-s/e) across admin components.
  • Standardize @cloudflare/kumo dependency versioning via pnpm catalog and bump to ^1.18.0 for both admin + blocks.
  • Add a few targeted RTL-specific tweaks (e.g., sidebar label alignment, trigger rotation).

Reviewed changes

Copilot reviewed 51 out of 52 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
pnpm-workspace.yaml Adds @cloudflare/kumo to the pnpm catalog for consistent version pinning.
pnpm-lock.yaml Updates lockfile to use catalog specifiers and resolves @cloudflare/kumo@1.18.0 (plus transitive updates).
packages/blocks/package.json Switches @cloudflare/kumo to catalog: (aligning dependency management).
packages/admin/package.json Switches @cloudflare/kumo to catalog: (aligning dependency management).
.changeset/fresh-flowers-visit.md Adds a changeset entry describing the RTL support feature (admin).
packages/admin/src/routes/bylines.tsx Uses text-start for RTL-friendly alignment.
packages/admin/src/components/users/UserList.tsx Converts left/pl/text-left to start/ps/text-start utilities in the user list UI.
packages/admin/src/components/users/UserDetail.tsx Moves the detail panel to end-0 and updates text-right to text-end.
packages/admin/src/components/users/RoleBadge.tsx Converts ml-* to ms-* for logical spacing.
packages/admin/src/components/users/InviteUserModal.tsx Converts right-* to end-* for RTL-friendly positioning.
packages/admin/src/components/settings/AllowedDomainsSettings.tsx Converts right-* to end-* for RTL-friendly positioning.
packages/admin/src/components/editor/PluginBlockNode.tsx Converts -left-* to -start-* for RTL-friendly gutter positioning.
packages/admin/src/components/editor/ImageNode.tsx Converts right/left to end/start for overlay positioning.
packages/admin/src/components/editor/ImageDetailPanel.tsx Converts panel positioning/border to logical equivalents (end-0, border-s).
packages/admin/src/components/editor/DocumentOutline.tsx Converts indentation and alignment to logical (ps-*, text-start).
packages/admin/src/components/editor/BlockMenu.tsx Converts menu item alignment to text-start.
packages/admin/src/components/comments/CommentInbox.tsx Converts search/icon positioning, alignment, and ml-auto to logical equivalents.
packages/admin/src/components/comments/CommentDetail.tsx Converts side panel border/position to logical (end-0, border-s).
packages/admin/src/components/WordPressImport.tsx Converts table alignment and left borders/margins to logical equivalents.
packages/admin/src/components/Widgets.tsx Converts close button positioning and item alignment to logical equivalents.
packages/admin/src/components/WelcomeModal.tsx Converts close button positioning to end-*.
packages/admin/src/components/ThemeMarketplaceDetail.tsx Converts icon margins and absolute positioning to logical equivalents.
packages/admin/src/components/ThemeMarketplaceBrowse.tsx Converts search icon padding/margins to logical equivalents.
packages/admin/src/components/TaxonomySidebar.tsx Converts checkbox spacing and dropdown positioning/alignment to logical equivalents.
packages/admin/src/components/TaxonomyManager.tsx Converts label spacing and dialog close positioning to logical equivalents.
packages/admin/src/components/Sidebar.tsx Converts nav label alignment to text-start and adds targeted label overrides for Kumo sidebar group labels.
packages/admin/src/components/SetupWizard.tsx Converts ml-* to ms-* for step indicator spacing.
packages/admin/src/components/SeoImageField.tsx Converts overlay action positioning to end-*.
packages/admin/src/components/Sections.tsx Converts close button/search icon/padding to logical equivalents.
packages/admin/src/components/SectionPickerModal.tsx Converts close button/search icon/padding and card alignment to logical equivalents.
packages/admin/src/components/SandboxedPluginPage.tsx Converts toast positioning to logical end-*.
packages/admin/src/components/RevisionHistory.tsx Converts button alignment to text-start.
packages/admin/src/components/RepeaterField.tsx Converts ml-* to ms-* for label meta text.
packages/admin/src/components/Redirects.tsx Converts close button/search UI/alignment and badges spacing to logical equivalents.
packages/admin/src/components/PortableTextEditor.tsx Converts slash menu alignment and popover positioning to logical equivalents.
packages/admin/src/components/PluginManager.tsx Converts icon margins to logical (me-*).
packages/admin/src/components/MenuList.tsx Converts close button positioning and icon margin to logical equivalents.
packages/admin/src/components/MenuEditor.tsx Converts close button positioning to end-*.
packages/admin/src/components/MediaPickerModal.tsx Converts close button/search icon/padding and gradients positioning to logical equivalents.
packages/admin/src/components/MediaLibrary.tsx Converts search UI/table alignment and card alignment to logical equivalents.
packages/admin/src/components/MediaDetailPanel.tsx Converts panel positioning/border and header padding to logical equivalents.
packages/admin/src/components/MarketplacePluginDetail.tsx Converts install icon margin and lightbox positioning to logical equivalents.
packages/admin/src/components/MarketplaceBrowse.tsx Converts search icon/padding and retry icon margin to logical equivalents.
packages/admin/src/components/LoginPage.tsx Converts provider button spacing ml-* to ms-*.
packages/admin/src/components/Header.tsx Adds RTL rotation for the sidebar trigger and converts icon margin + menu alignment to logical equivalents.
packages/admin/src/components/FieldEditor.tsx Converts close button positioning, option card alignment, and ml-auto to logical equivalents.
packages/admin/src/components/ContentTypeList.tsx Converts icon margins, label spacing, header/cell alignment to logical equivalents.
packages/admin/src/components/ContentTypeEditor.tsx Converts label spacing and drag handle spacing to logical equivalents.
packages/admin/src/components/ContentPickerModal.tsx Converts close button/search icon/padding and list alignment to logical equivalents.
packages/admin/src/components/ContentList.tsx Converts add button icon margin, search UI, and table alignment to logical equivalents.
packages/admin/src/components/ContentEditor.tsx Converts fixed header left/right to start/end and icon/text margins to logical equivalents.
packages/admin/src/components/CapabilityConsentDialog.tsx Converts ml-* to ms-* for “NEW” label spacing.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 117 to 120
"fixed end-0 top-0 z-50 flex h-full w-full max-w-md flex-col bg-kumo-base shadow-xl",
"transform transition-transform duration-200",
isOpen ? "translate-x-0" : "translate-x-full",
)}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

end-0 makes the panel attach to the logical end (left in RTL), but the hidden/off-screen transform still uses translate-x-full, which always moves toward the physical right. This will cause the panel to slide the wrong direction in RTL if you ever rely on the closed transform state. Use direction-aware transforms (e.g., ltr:translate-x-full rtl:-translate-x-full) so the off-screen state matches end-0.

Copilot uses AI. Check for mistakes.
Comment thread packages/admin/src/components/editor/ImageDetailPanel.tsx Outdated
"fixed inset-y-0 right-0 w-96 bg-kumo-base border-l shadow-xl z-50",
"fixed inset-y-0 end-0 w-96 bg-kumo-base border-s shadow-xl z-50",
"flex flex-col",
"animate-in slide-in-from-right duration-200",
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

This panel is anchored with end-0 (left side in RTL), but it still uses slide-in-from-right. That will animate from the wrong side when dir="rtl". Make the enter animation direction-aware (e.g., ltr:slide-in-from-right rtl:slide-in-from-left) so the motion matches the logical edge.

Suggested change
"animate-in slide-in-from-right duration-200",
"animate-in ltr:slide-in-from-right rtl:slide-in-from-left duration-200",

Copilot uses AI. Check for mistakes.
Comment thread packages/blocks/package.json
@github-actions github-actions bot removed the size/L label Apr 14, 2026
Adapts tests for the Dialog.Portal rendering model (renders outside
screen.container) and the data-base-ui-inert overlay that blocks
Playwright pointer events.
@github-actions
Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

@ascorbic ascorbic merged commit 913cb62 into emdash-cms:main Apr 15, 2026
27 checks passed
Copy link
Copy Markdown
Collaborator

@ascorbic ascorbic left a comment

Choose a reason for hiding this comment

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

Amazing work. Thanks

@emdashbot emdashbot bot mentioned this pull request Apr 15, 2026
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.

4 participants