// UiProvider — the single place an app injects presentation context. Reactive // access goes through the Solid adapter, so this file imports only solid types — and only TYPES // from `@ultimat3/i18n`: `directionOf` is core's, because a value import of the i18n barrel is // the framework catalog in every island chunk with a provider (issue #490). import { directionOf } from '@ultimat3/core'; import type { Locale, Translator } from '@ultimat3/i18n'; import type { TimeZone } from '@ultimat3/time'; import type { JSX } from 'solid-js'; import { providerNeedsRuntimeError } from '../errors'; import type { Theme } from '../tokens/tokens'; import { fallbackTranslator, UI_DEFAULT_CURRENCY, UI_DEFAULT_LOCALE, UI_DEFAULT_TIME_ZONE, type UiContextValue, uiContext, } from './context'; import { hasSolidRuntime } from './runtime-slot'; import { solid } from './solid-adapter'; export interface UiProviderProps { theme?: Theme | undefined; locale?: Locale | undefined; timeZone?: TimeZone | undefined; currency?: string | undefined; t?: Translator | undefined; children?: JSX.Element | undefined; } /** * Also reflects `lang` and `dir` onto , so the document, native form * controls, and every logical property agree with the injected locale. * * Client-only, and loud about it: `solid()` hands a server render an inert runtime so every other * component still renders, but a Provider is the one thing that inert runtime cannot honour. On * the server the same values reach `useUi()` from the request context instead. */ export function UiProvider(props: UiProviderProps): JSX.Element { if (!hasSolidRuntime()) throw providerNeedsRuntimeError(); const rt = solid(); const value = rt.createMemo(() => { const locale = props.locale ?? UI_DEFAULT_LOCALE; return { theme: props.theme ?? 'light', locale, timeZone: props.timeZone ?? UI_DEFAULT_TIME_ZONE, currency: props.currency ?? UI_DEFAULT_CURRENCY, dir: directionOf(locale), t: props.t ?? fallbackTranslator(locale), }; }); rt.createEffect(() => { if (typeof document === 'undefined') return; const root = document.documentElement; const next = value(); root.setAttribute('lang', next.locale); root.setAttribute('dir', next.dir); if (props.theme !== undefined) root.setAttribute('data-theme', next.theme); }); const Ctx = uiContext(); return {props.children}; }