Skip to content

feat(docs): add RTL decorator#6188

Merged
rubencarvalho merged 4 commits intomainfrom
ruben/gen2-storybbok-rtl
Apr 21, 2026
Merged

feat(docs): add RTL decorator#6188
rubencarvalho merged 4 commits intomainfrom
ruben/gen2-storybbok-rtl

Conversation

@rubencarvalho
Copy link
Copy Markdown
Contributor

@rubencarvalho rubencarvalho commented Apr 17, 2026

Description

Adds a dedicated Direction Storybook toolbar control (auto / LTR / RTL) alongside the existing Language control. Direction resolution:

  • Auto — follows locale (RTL for Arabic, Hebrew, and Farsi when applicable; otherwise LTR).
  • LTR / RTL — explicit override, independent of language (so typography/font kit can stay on one locale while layout direction is forced).

The withLanguageWrapper decorator applies the resolved direction on the preview root using both:

  • dir on document.documentElement (semantic / bidi), and
  • direction via inline CSS on the same element (explicit visual direction).

context.globals.resolvedTextDirection is set so stories or tooling can read the final ltr | rtl value. The globalsUpdated listener was updated so direction changes apply even when the decorator does not re-run (e.g. some docs flows).

Motivation and context

Language alone implied RTL for some locales, which made it awkward to test LTR vs RTL without changing locale, especially when pairing a specific font/locale with a fixed reading direction. A separate Direction control fixes that.

This also unblocks Chromatic VRT: you can template permutations (e.g. theme × scale × explicit LTR/RTL) without relying on switching to an RTL locale only to get dir/layout. Stories or Chromatic configuration can key off globals.textDirection / resolvedTextDirection.

Author's checklist

  • I have read the CONTRIBUTING and PULL_REQUESTS documents.
  • I have reviewed the Accessibility Practices for this feature, see: ARIA Practices (toolbar sets document dir; no new interactive component in the library.)
  • I have added automated tests to cover my changes.
  • I have included a well-written changeset if my change needs to be published.
  • I have included updated documentation if my change required it (consider a short note in the Fonts / customization guide about Direction vs Language).

Reviewer's checklist

Manual review test cases

  • Direction toolbar + document root

    1. Open any 2nd-gen Storybook story.
    2. Set Language to English and Direction to RTL.
    3. Inspect <html>: expect dir="rtl" and inline direction: rtl (or equivalent).
    4. Set Direction to LTR; expect dir="ltr" and LTR CSS.
  • Auto follows locale

    1. Set Direction to Auto.
    2. Switch Language between English and Arabic (or Hebrew).
    3. Expect RTL when locale is RTL and LTR for English, without manual Direction overrides fighting Auto.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 17, 2026

⚠️ No Changeset found

Latest commit: c0b6d22

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 17, 2026

📚 Branch Preview Links

🔍 First Generation Visual Regression Test Results

When a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:

Deployed to Azure Blob Storage: pr-6188

If the changes are expected, update the current_golden_images_cache hash in the circleci config to accept the new images. Instructions are included in that file.
If the changes are unexpected, you can investigate the cause of the differences and update the code accordingly.

@rubencarvalho rubencarvalho added Status:Ready for review PR ready for review or re-review. 2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. labels Apr 17, 2026
@rubencarvalho rubencarvalho marked this pull request as ready for review April 17, 2026 16:35
@rubencarvalho rubencarvalho requested a review from a team as a code owner April 17, 2026 16:35
Copy link
Copy Markdown
Collaborator

@pfulton pfulton left a comment

Choose a reason for hiding this comment

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

Looks great. I clicked-through to the deployed Storybook instance and was able to follow the testing instructions. Everything worked as expected.

Thanks for taking care of this!

return textDirection;
}

return RTL_LANGS.has(String(lang ?? 'en-US')) ? 'rtl' : 'ltr';
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.

?? only short‑circuits on null | undefined. When lang === false this evaluates to String(false) === 'false', which never matches RTL_LANGS. You get LTR for the right reason by accident. You can use lang || 'en-US' to mirror the convention used in applyLanguageAndFontKit (lang ? String(lang) : 'en-US')

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated!

context.globals.textDirection = isRTL ? 'rtl' : 'ltr';
// Keep an explicit, resolved direction available for stories.
const resolvedTextDirection = resolveTextDirection(lang, textDirection);
context.globals.resolvedTextDirection = resolvedTextDirection;
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.

This can be an anti-pattern of mutating context.globals during render. If you want to keep this would you like to add a comment explaining the contract. I just want to avoid the future contributors to propagate this pattern.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

You're right - no need for this now, so I removed it :)

Comment on lines +53 to +54
root.setAttribute('dir', textDirection);
root.style.direction = textDirection;
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.

dir="rtl" on an element already maps to direction: rtl via the UA stylesheet. This will add an inline specificity which can fight overrides further down. Can you show me an example where the dir attribute alone is not propagating?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

updated!

@rubencarvalho rubencarvalho requested a review from Rajdeepc April 20, 2026 17:30
lang: string | false,
textDirection: 'ltr' | 'rtl'
): void {
const langAttr = lang ? String(lang) : 'en-US';
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.

nit: This could also be updated to lang || 'en-US', since the truthy path is always going to be a string.

Also what happens if you are passed a invalid lang string? I know this is just storybook, but we might want to consider some stronger type safety.

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.

If we pass an invalid string here right now it will silently LTR. The set check is RTL_LANGS.has(String(lang || 'en-US')), so any string not in {'ar','fa','he'} → 'ltr'

Copy link
Copy Markdown
Contributor

@Rajdeepc Rajdeepc left a comment

Choose a reason for hiding this comment

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

Looks good!

@rubencarvalho rubencarvalho enabled auto-merge (squash) April 21, 2026 11:55
@rubencarvalho rubencarvalho merged commit 2dcb68e into main Apr 21, 2026
29 of 31 checks passed
@rubencarvalho rubencarvalho deleted the ruben/gen2-storybbok-rtl branch April 21, 2026 12:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2nd gen These issues or PRs map to our 2nd generation work to modernizing infrastructure. Status:Ready for review PR ready for review or re-review.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants