# Capability Spec: react-ui **Package**: `@suaveplan/react-ui` **Status**: PROPOSED > Every requirement carries a `**Verified by:**` line at authoring time. (See `openspec/AGENTS.md` Section 13.) ## ADDED Requirements ### Requirement: ReactUiProvider composes Translation, Theme, and PackRegistry providers The package SHALL expose `ReactUiProvider` as an opinionated composition of `` (from `@suaveplan/react-i18n`), ``, and `` mounted in the order `Translation → Theme → PackRegistry`. The provider SHALL accept `i18n: I18nInstance`, `themes: readonly ThemePlugin[]`, `defaultTheme: string`, optional `packs: readonly ComponentPack[]`, optional `components` for runtime per-pack overrides, optional `reactUiOverrides: Partial>>>`, and optional `scriptNonce: string` for CSP-aware FOUC prevention. On mount, it SHALL await the lazy `reactUiBundles[locale]()` import for the active locale and call `i18n.addResourceBundle('react-ui', bundle)` before rendering children. On `languageChanged`, it SHALL load the new locale's bundle and swap. The mount SHALL emit an OTel span `react_ui.provider.mount` with attributes `{ theme, pack.count, locale }`. #### Scenario: provider composition order is Translation → Theme → PackRegistry - **GIVEN** `{children}` - **WHEN** rendered - **THEN** the React tree contains, from outer to inner: `TranslationProvider`, `ThemeProvider`, `PackRegistryProvider`, `children` #### Scenario: bundled translations auto-register on mount - **GIVEN** `` mounted with active locale `en-GB` - **WHEN** the lazy `reactUiBundles['en-GB']()` import resolves - **THEN** `i18n.getResourceBundle('en-GB', 'react-ui')` contains every key from `src/locales/en-GB.json` #### Scenario: reactUiOverrides win over auto-registered keys - **GIVEN** `` with the active locale `en-GB` - **WHEN** `t('react-ui.pagination.next')` is called - **THEN** the result equals `'Forward →'` #### Scenario: provider mount emits OTel span - **GIVEN** an in-memory `MeterProvider` and a real `Tracer` - **WHEN** the provider mounts with `{ theme: 'light', pack.count: 1, locale: 'en-GB' }` - **THEN** a span `react_ui.provider.mount` is recorded with those attributes **Verified by:** `packages/react/react-ui/src/provider/react-ui-provider/react-ui-provider.test.tsx::"composition order"` AND `packages/react/react-ui/src/provider/react-ui-provider/react-ui-provider.test.tsx::"bundled translations auto-register"` AND `packages/react/react-ui/src/provider/react-ui-provider/react-ui-provider.test.tsx::"reactUiOverrides win"` AND `packages/react/react-ui/src/provider/react-ui-provider/react-ui-provider.test.tsx::"mount span emitted"` --- ### Requirement: ThemeProvider mounts a theme registry and prevents FOUC `` SHALL accept `themes: readonly ThemePlugin[]`, `defaultTheme: string`, optional `storageKey: string` (default `'suaveplan-theme'`), optional `enableSystem: boolean`, optional `attribute: string` (default `'data-theme'`), and optional `scriptNonce: string`. On mount, it SHALL inject an inline `