# `useToastSonnerBridge` _(no submodules)_ ## Purpose Bridge hook that exposes the legacy chassis `useToast` API on top of `sonner.toast`. The original chassis `useToast` (Wave 2) ran a small `useSyncExternalStore`-backed queue that a separate root-level renderer painted; Wave 3g adopts `sonner` as the canonical toast surface (per shadcn skill rule) so the chassis-side queue is no longer the canonical path. This bridge lets consumers migrate one import at a time — call sites that already imported the legacy `useToast` hook keep working, and new call sites that want the sonner-native surface adopt this bridge instead. The two routes funnel through the same `react_ui.toast.shown_total{toast.kind=...}` counter so observability dashboards never double-count. ## Features - `bridge.toast({ titleKey, descriptionKey?, kind? })` — branded translation keys, resolved against the active ``, dispatched to sonner. - `bridge.dismiss(id?)` — dismiss a specific toast id, or every active toast when called without arguments. - Kind-aware dispatch: `success`, `error`, `info`, `warning` route to the matching `toast.` method; everything else is dispatched via the default `toast()` callable. - Zero internal state — the bridge is a stateless adapter; the authoritative queue lives inside sonner. ## Usage: Basic Example ```tsx import { Sonner, useToastSonnerBridge, } from "@suaveplan/react-ui"; function SaveButton(): JSX.Element { const { toast } = useToastSonnerBridge(); return ( <> ); } ``` ## Usage: Advanced Example ```tsx import { Sonner, useToastSonnerBridge, } from "@suaveplan/react-ui"; import { useEffect } from "react"; function NetworkBoundary(): JSX.Element { const { toast, dismiss } = useToastSonnerBridge(); useEffect(() => { const id = toast({ titleKey: "react-ui.loading", descriptionKey: "react-ui.empty.noResults", kind: "warning", }); const timer = setTimeout(() => dismiss(id), 4000); return () => clearTimeout(timer); }, [toast, dismiss]); return ; } ``` ## API Reference ### `useToastSonnerBridge(): UseToastSonnerBridgeReturn` Returns: - `toast(input: BridgeToastInput): string | number` — emits a toast via sonner. The returned id is the same id sonner assigns; pass it to `dismiss` to retire the specific toast. - `dismiss(id?: string | number): void` — dismisses one toast by id, or all toasts when `id` is `undefined`. ### `BridgeToastInput` - `titleKey: TranslationKey` — REQUIRED branded key resolved against the active i18n catalog. - `descriptionKey?: TranslationKey` — optional secondary line, also resolved against i18n. - `kind?: ToastKind` — `'default' | 'success' | 'error' | 'info' | 'warning'`. Defaults to `'default'`. ## Implementation Notes - The bridge MUST be called inside a `` because it reads `useTranslation()` to resolve the branded keys; outside a provider it throws `REACT_I18N.NO_PROVIDER`. - The bridge does NOT instrument OTel directly — the underlying `toast` re-export (which records the counter) is the single point of attribution so we never double-count when the bridge fans out to a kind-specific method. - The bridge does NOT read sonner's `useSonner()` hook because the upstream API does not expose a way to subscribe to a SPECIFIC toast id, and the chassis bridge has no use for the global toast list at call time — `toast.dismiss(id)` is sufficient for the UX surface. - Memoised `useCallback` wrappers keep the returned object referentially stable across renders so consumers using the bridge inside a `useEffect` dependency array do not re-fire on every parent render.