first commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# `useValidationMessageBridge`
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
Centralised resolver factory turning a `SuaveplanError` (or any thrown value) into a locale-resolved user-facing message. Mirrors the resolution rules of `useErrorMessage` from `@suaveplan/react-i18n` but returns a function — so a single hook call gives you a resolver you can apply to many errors per render: a list of validation errors on a form, a batch of toasts, a fan-out of notifications, or a status panel summarising recent failures. Every UI surface in `react-ui` (Toast, Alert, Dialog, ConfirmDeleteDialog) that needs to render an error should resolve through this bridge so the catalog-lookup behaviour stays consistent across the chassis.
|
||||
|
||||
## Features
|
||||
|
||||
- One hook call yields a resolver suitable for many errors.
|
||||
- Walks the `cause` chain to surface the deepest `SuaveplanError`.
|
||||
- Catalog lookup (`errors:<code>`) on hit; falls back to `error.message` on miss.
|
||||
- Coerces non-`Error` inputs (strings, undefined) without throwing.
|
||||
- Stable function reference across renders (memoized by `useCallback`).
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```tsx
|
||||
import { useValidationMessageBridge } from "@suaveplan/react-ui";
|
||||
|
||||
function FormErrors({ errors }: { errors: SuaveplanError[] }) {
|
||||
const resolve = useValidationMessageBridge();
|
||||
return (
|
||||
<ul>
|
||||
{errors.map((e, i) => <li key={i}>{resolve(e)}</li>)}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
Render a batch of validation errors inside an Alert with the bridge resolver:
|
||||
|
||||
```tsx
|
||||
function ValidationSummary({ errors }: { errors: unknown[] }) {
|
||||
const resolve = useValidationMessageBridge();
|
||||
return (
|
||||
<Alert variant="destructive">
|
||||
<AlertTitle>Please fix the following</AlertTitle>
|
||||
<AlertDescription>
|
||||
<ul>
|
||||
{errors.map((err, i) => (
|
||||
<li key={i}>{resolve(err)}</li>
|
||||
))}
|
||||
</ul>
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
A try/catch handler that surfaces a toast with the resolved message:
|
||||
|
||||
```tsx
|
||||
function useSubmit() {
|
||||
const resolve = useValidationMessageBridge();
|
||||
const { toast } = useToast();
|
||||
return useCallback(async (input: FormValues) => {
|
||||
try {
|
||||
await save(input);
|
||||
} catch (err) {
|
||||
toast({ variant: "destructive", description: resolve(err) });
|
||||
}
|
||||
}, [resolve, toast]);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `useValidationMessageBridge(): ValidationMessageResolver`
|
||||
|
||||
Returns `(error: unknown) => string`. Resolution order:
|
||||
|
||||
1. `null` / `undefined` → `""`.
|
||||
2. Walk cause chain → first `SuaveplanError` wins. Look up `errors:<code>`; on hit return the translation, on miss return the surfaced error's `.message`.
|
||||
3. Plain `Error` → `error.message`.
|
||||
4. `string` → itself.
|
||||
5. Anything else → `""`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The hook reads the i18n instance via `useI18n()` and memoizes the resolver with `useCallback([i18n])` so the function reference is stable as long as the i18n instance is. Languages-changed events bump i18n's snapshot counter; the bridge's resolver re-binds when that propagates so subsequent calls see the new locale's catalog.
|
||||
- Cause-chain walking is bounded at depth 10 to prevent runaway loops on accidentally-cyclic error structures.
|
||||
- The bridge does NOT perform any side effects (no logging, no telemetry). For metric emission on errors, wrap the call site or compose with `@suaveplan/logger`.
|
||||
Reference in New Issue
Block a user