Skip to content

feat(core): RTL direction API (useDirection + getLocaleDirection + dir prop)#4269

Open
nynexman4464 wants to merge 1 commit into
mainfrom
nynexman4464/feat/rtl-direction-api
Open

feat(core): RTL direction API (useDirection + getLocaleDirection + dir prop)#4269
nynexman4464 wants to merge 1 commit into
mainfrom
nynexman4464/feat/rtl-direction-api

Conversation

@nynexman4464

Copy link
Copy Markdown
Contributor

Summary

Phase 1 of astryx RTL support (refs #4116). Adds the small foundation API — hook, server helper, provider surface — plus Pagination as the reference implementation and a Storybook Direction toolbar. Actual component CSS migrations (borders, chevrons, calendar range pills, slider math) land in follow-up PRs.

API

// Hook — client-side, reads ambient direction from provider (returns 'ltr' outside a provider)
const dir = useDirection();

// Server helper — pure function, no context, safe for React Server Components / Next.js layouts
const dir = getLocaleDirection('ar'); // 'rtl'

// Provider — direction is auto-derived from the locale; `dir` prop overrides
<InternationalizationProvider locale="ar"></InternationalizationProvider>          // rtl
<InternationalizationProvider locale="en" dir="rtl"></InternationalizationProvider> // rtl override

Direction is computed via Intl.Locale.getTextInfo() (CLDR-backed, covers the full RTL BCP 47 tag set — ar, he, fa, ur, ps, sd, yi, ug, dv, ku — not just a hardcoded shortlist). A try/catch fallback returns 'ltr' for exotic runtimes; no polyfill needed on React 19's browser baseline.

Design decisions

  • Single provider, two inputs. InternationalizationProvider accepts both locale and optional dir. The 99% case is locale="ar" and direction is derived automatically; the 1% case (RTL layout testing under an English catalog, forcing LTR for admin UIs, etc.) uses the explicit override.
  • Consumer wires <html dir> themselves. No useEffect mutating document.dir — that causes SSR hydration mismatch and misses portaled overlays. This matches every mainstream React library (react-aria, Radix, MUI, Chakra, Ant Design, Mantine, Fluent).
  • Hook is read-only. No setDirection / toggleDirection; consumers manage direction state via their own store or Next.js locale.
  • useDirection() returning the primitive string matches Radix and Mantine's shape.

Reference implementation: Pagination

Pagination's prev/next chevron icons now flip under RTL. The aria-labels stay semantic (@astryx.pagination.previous / @astryx.pagination.next) — only the visual arrow direction changes. A RightToLeft story demonstrates the behavior.

Storybook

New global Direction toolbar toggle between LTR and RTL. Wraps every story in <InternationalizationProvider dir={value}> and applies dir={value} to the story container. Existing decorators (theme, color mode) are unchanged.

Docs

packages/cli/docs/internationalization.doc.mjs gains a new "Direction" section covering useDirection(), getLocaleDirection(), and the dir prop.

Testing

  • packages/core/src/i18n/__tests__/getLocaleDirection.test.ts — 8 cases: en → ltr, ar/he/fa/ur → rtl, pt-BR/zh-CN → ltr, invalid locale falls back to ltr.
  • packages/core/src/i18n/__tests__/useDirection.test.tsx — hook returns provider value; explicit dir overrides derived; missing provider returns ltr.
  • Full i18n suite: 40/40. Pagination: 64/64. pnpm --filter '@astryxdesign/core' typecheck: clean. pnpm check:repo: PASS.

Follow-ups (not this PR)

Per the RTL migration plan, remaining work:

  • PR 2 — logical-props sweep (textAlign, borders, insets) + directional icon foundation
  • PR 3 — Calendar range pills
  • PR 4 — Slider + Resizable behavioral RTL
  • PR 5 — Snapshot matrix expansion

…r prop)

Adds Phase 1 of RTL support:
- `direction: 'ltr' | 'rtl'` on InternationalizationContext value
- `dir?: 'ltr' | 'rtl'` prop on InternationalizationProvider (overrides locale-derived default)
- `useDirection()` hook — returns 'ltr' outside a provider (matches useTranslator fallback pattern)
- `getLocaleDirection(locale)` — server-safe helper for RSC / <html dir>
- Pagination flips chevron prev/next icons under RTL
- Storybook `dir` global toolbar toggle (LTR / RTL)
- Pagination `RightToLeft` story
- Docs updated with the new API

Direction is derived from Intl.Locale.getTextInfo() with try/catch fallback
to 'ltr'. Explicit `dir` prop always wins.

Ref #4116
@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jul 23, 2026
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview, Comment Jul 23, 2026 9:52pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

Modified Components

Pagination · View in Storybook
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 483 -
Complexity N/A Very High (59) -
i18n
Metric Before After Delta
Bundle Size (ESM) N/A N/A N/A
Lines of Code N/A 198 -
Complexity N/A Low (3) -

Bundle Size Summary

Package Size (ESM) Size (CJS) Gzipped
@astryxdesign/core N/A 4.7KB 0B

Accessibility Audit

Status: 1 accessibility violation(s) found — 1 moderate.

Pagination - 1 issue(s)
  • 🟡 moderate: Ensure landmarks are unique
    • Rule: landmark-unique · Affects 1/15 stories · Learn more

Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

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

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant