Initial Commit
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
# useDirection
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`useDirection()` returns the writing direction (`'ltr'` / `'rtl'`) for
|
||||
the active locale. Composes `useLocale` (so it inherits the underlying
|
||||
`useSyncExternalStore` subscription) and runs the locale through
|
||||
`@suaveplan/i18n`'s `getTextDirection` helper. The single-source-of-truth
|
||||
for which locales are RTL lives in the i18n core's `RTL_LOCALES` set —
|
||||
the React surface does not duplicate the list.
|
||||
|
||||
The hook is the canonical primitive for direction-sensitive UI: setting
|
||||
`<html dir="...">`, mirroring icon strips, swapping margin-left for
|
||||
margin-right in a CSS module, and so on. A locale change like
|
||||
`setLocale('ar-AE')` flips the result to `'rtl'` on the same React
|
||||
commit cycle as the bus emission, so the UI re-mirrors atomically with
|
||||
the new translations.
|
||||
|
||||
## Features
|
||||
|
||||
- Returns `{ direction, locale }` — both kept in sync with the active locale.
|
||||
- `'ltr'` / `'rtl'` resolution via the i18n core's `getTextDirection`.
|
||||
- `direction` defaults to `'ltr'` on the production no-Provider fallback (the safer default for unknown locales).
|
||||
- Memoised on the locale string so a no-op re-render does not re-call `getTextDirection`.
|
||||
- Re-renders on `languageChanged` via the inherited `useLocale` subscription.
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```tsx
|
||||
import { useDirection } from "@suaveplan/react-i18n";
|
||||
|
||||
export function ChatBubble(props: { readonly children: React.ReactNode }) {
|
||||
const { direction } = useDirection();
|
||||
return (
|
||||
<div
|
||||
dir={direction}
|
||||
style={{ textAlign: direction === "rtl" ? "right" : "left" }}
|
||||
>
|
||||
{props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
For document-level mirroring set the `<html dir>` attribute from a
|
||||
top-level effect that mirrors the hook's output. The pattern below
|
||||
keeps the markup in sync without needing every component to be
|
||||
direction-aware.
|
||||
|
||||
```tsx
|
||||
import { useEffect } from "react";
|
||||
import { useDirection } from "@suaveplan/react-i18n";
|
||||
|
||||
export function HtmlDirectionSync(): null {
|
||||
const { direction, locale } = useDirection();
|
||||
useEffect(() => {
|
||||
const root = document.documentElement;
|
||||
if (locale !== undefined) root.lang = locale;
|
||||
root.dir = direction;
|
||||
}, [direction, locale]);
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `useDirection(): UseDirectionReturn`
|
||||
|
||||
- **Returns**: `{ direction, locale }`.
|
||||
- `direction: 'ltr' | 'rtl'` — derived from `getTextDirection(locale)`. Defaults to `'ltr'` when `locale === undefined`.
|
||||
- `locale: string | undefined` — current active locale, mirrored from `useLocale().locale`.
|
||||
- **Throws**: `ReactI18nError(REACT_I18N.NO_PROVIDER)` outside a `<TranslationProvider>` in dev mode (inherited from `useLocale → useI18n`).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The lookup is wrapped in `useMemo` keyed on the locale string. `getTextDirection` is cheap (a single `Set.has` after a string split), but the memo also keeps the returned object reference stable across re-renders that did not change the locale, which keeps `React.memo`-wrapped descendants from re-rendering.
|
||||
- The hook deliberately delegates the RTL list to `@suaveplan/i18n` instead of duplicating it. New RTL scripts added to the upstream `RTL_LOCALES` table propagate automatically — no React-side maintenance required.
|
||||
- The fallback to `'ltr'` on the no-Provider production path matches the broader package contract: end-users see degraded but non-broken UI when configuration is missing.
|
||||
Reference in New Issue
Block a user