first commit
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# `<ReactUiProvider>` — opinionated chassis composition
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
The opinionated 95%-case wrapper for the chassis. Composes the three
|
||||
primitive providers in the canonical order `<TranslationProvider>` →
|
||||
`<ThemeProvider>` → `<PackRegistryProvider>` and adds an effect-driven
|
||||
loader that auto-registers the chassis bundled translations into the
|
||||
active i18n catalog (with optional consumer overrides applied on top).
|
||||
Emits the `react_ui.provider.mount` OTel span on every mount.
|
||||
|
||||
## Features
|
||||
|
||||
- 15-line provider composition in the right order
|
||||
- Auto-registration of the bundled chassis locale on mount
|
||||
- Consumer overrides via `reactUiOverrides` win over the default
|
||||
bundle keys
|
||||
- Re-loads the bundle on `languageChanged` so a runtime locale switch
|
||||
picks up the matching translations automatically
|
||||
- Records `react_ui.locale.bundle.load_total{locale, outcome}` and
|
||||
`react_ui.locale.bundle.load_duration_ms{locale}` per load
|
||||
- Records the `react_ui.provider.mount` span carrying `theme`,
|
||||
`pack.count`, and `locale` attributes
|
||||
- Defers to `<TranslationProvider>` for the i18n instance (the
|
||||
Provider is mode `caller-managed` because we always pass `i18n`)
|
||||
|
||||
## Usage: Basic example
|
||||
|
||||
```tsx
|
||||
import { ReactUiProvider } from "@suaveplan/react-ui/provider";
|
||||
import { lightTheme } from "@suaveplan/react-ui/theme";
|
||||
import { createI18n } from "@suaveplan/i18n/plugin";
|
||||
|
||||
const i18n = createI18n({ defaultLocale: "en-GB" });
|
||||
|
||||
<ReactUiProvider i18n={i18n} themes={[lightTheme]} defaultTheme="light">
|
||||
<App />
|
||||
</ReactUiProvider>;
|
||||
```
|
||||
|
||||
## Usage: Advanced example
|
||||
|
||||
```tsx
|
||||
import { ReactUiProvider } from "@suaveplan/react-ui/provider";
|
||||
import {
|
||||
darkTheme,
|
||||
highContrastTheme,
|
||||
lightTheme,
|
||||
} from "@suaveplan/react-ui/theme";
|
||||
import { authPack } from "@suaveplan/react-ui-pack-auth";
|
||||
|
||||
<ReactUiProvider
|
||||
i18n={i18n}
|
||||
themes={[lightTheme, darkTheme, highContrastTheme]}
|
||||
defaultTheme="light"
|
||||
packs={[authPack]}
|
||||
components={{ auth: { LoginForm: AcmeLoginForm } }}
|
||||
reactUiOverrides={{
|
||||
"en-GB": {
|
||||
"react-ui.themeToggle.label": "Appearance",
|
||||
},
|
||||
}}
|
||||
scriptNonce={cspNonce}
|
||||
>
|
||||
<App />
|
||||
</ReactUiProvider>;
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `<ReactUiProvider>` — props per `ReactUiProviderProps`:
|
||||
- `i18n: I18nInstance` — required
|
||||
- `themes: ReadonlyArray<ThemePlugin>` — required
|
||||
- `defaultTheme: string` — required
|
||||
- `packs?: ReadonlyArray<ComponentPack>`
|
||||
- `components?: RuntimeComponentOverride`
|
||||
- `reactUiOverrides?: ReactUiLocaleOverrides`
|
||||
- `logger?: PackLoggerLike`
|
||||
- `scriptNonce?: string`
|
||||
- `storageKey?: string`
|
||||
- `attribute?: string`
|
||||
- `children: ReactNode`
|
||||
- `type ReactUiLocaleOverrides = Partial<Record<SupportedLocale, Partial<Record<TranslationKey, string>>>>`
|
||||
|
||||
## Implementation notes
|
||||
|
||||
The bundle loader runs inside a `useEffect` and tracks an aborted-flag
|
||||
ref so a fast unmount does not leak a stale registration into the
|
||||
catalog. The `languageChanged` listener is registered on the i18n
|
||||
event bus rather than on the React reactive state because the i18n
|
||||
instance owns the locale truth — re-deriving from React state would
|
||||
introduce a one-render lag on every locale switch. The `span.end()`
|
||||
fires synchronously (before the lazy bundle resolves) so the trace
|
||||
boundary matches the React commit boundary; the bundle-load duration
|
||||
is captured separately via the histogram.
|
||||
Reference in New Issue
Block a user