feat(admin): add full RTL support to admin UI#565
Conversation
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)
…s to prevent drift from expected output
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>
…/i18n-dir-support-classes
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.
🦋 Changeset detectedLatest commit: a1b9f0b The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
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 |
Scope checkThis 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. |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/blocks
@emdash-cms/cloudflare
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
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.
There was a problem hiding this comment.
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/kumodependency versioning via pnpm catalog and bump to^1.18.0for 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.
| "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", | ||
| )} |
There was a problem hiding this comment.
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.
| "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", |
There was a problem hiding this comment.
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.
| "animate-in slide-in-from-right duration-200", | |
| "animate-in ltr:slide-in-from-right rtl:slide-in-from-left duration-200", |
Adapts tests for the Dialog.Portal rendering model (renders outside screen.container) and the data-base-ui-inert overlay that blocks Playwright pointer events.
Overlapping PRsThis PR modifies files that are also changed by other open PRs:
This may cause merge conflicts or duplicated work. A maintainer will coordinate. |
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.
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)[&>span]selector syntax andrtl:variantCloses #
Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runpnpm locale:extracthas been run (if applicable)AI-generated code disclosure
Screenshots / test output
Verified
pnpm typecheckandpnpm --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.