# OverlayHost

The one layer where every Dialog, Menu and toast appears, above native sheets. Mount it once at the root; open overlays from anywhere.

## Usage

Mount one `OverlayHost` at the root of your app, after your navigator and inside `ThemeProvider`:

```tsx
import { OverlayHost, ThemeProvider, type Theme } from "@terratcg/ui";
import { useSafeAreaInsets } from "react-native-safe-area-context";

export function Root({ theme }: { theme: Theme }) {
  const insets = useSafeAreaInsets();
  return (
    <ThemeProvider theme={theme}>
      <Navigator />
      <OverlayHost
        failureText="That didn't go through. Try again."
        insets={insets}
        toastInsetTop={insets.top}
      />
    </ThemeProvider>
  );
}
```

Then open overlays from anywhere, like `Alert.alert`, with no state or component of your own:

```tsx
const left = await showDialog({
  title: "Leave the call?",
  body: "The others stay connected.",
  confirm: "Leave",
  cancel: "Stay",
  tone: "destructive",
});
if (left) navigation.goBack();
```

`showDialog`, `showMenu`, `showToast` and `showTopToast` queue their overlay for the host. Each component's page covers its options.

## Props

### OverlayHostProps

| Prop             | Type                                                                             | Description                                                                                                                                     |
| ---------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `theme?`         | `Theme`                                                                          | The overlays' theme, for a host whose screen in front wears another one. The surrounding theme by default.                                      |
| `confirmIcon?`   | `((slot: ButtonIconSlot) => ReactNode) \| ReactNode`                             | The confirm key's default icon: primary keys carry one.                                                                                         |
| `failureText`    | `string`                                                                         | The sentence a Dialog shows when its action rejects, in the user's language. The error's own text is never shown: it is written for developers. |
| `onFailure?`     | `((error: unknown) => string \| undefined \| void)`                              | Hears every rejected Dialog action, where the host reports it. May return a sentence to show instead of `failureText`.                          |
| `insets?`        | `SafeInsets`                                                                     | The window's safe area: what a menu keeps clear of.                                                                                             |
| `holdToasts?`    | `boolean`                                                                        | Holds toasts while the app needs the screen to itself. Blocking overlays hold them on their own.                                                |
| `toastInsetTop?` | `number`                                                                         | How far toasts sit from the top of the window: the host's safe area.                                                                            |
| `toastIcons?`    | `Partial<Record<ToastTone, ((slot: ButtonIconSlot) => ReactNode) \| ReactNode>>` | Each toast tone's glyph.                                                                                                                        |

## What the host does

- **Above everything:** Dialogs and Menus are drawn in a `FullWindowOverlay` on iOS and a transparent `Modal` on Android, so they cover native sheets and headers. The layer is mounted only while something shows.
- **One at a time:** Dialogs and Menus wait their turn. Opening a Dialog dismisses the keyboard.
- **Toasts:** one queue at the top of the window, one toast at a time. Toasts wait while a Dialog or Menu is up, or while `holdToasts` is set; one already in view steps aside and comes back with its whole time.
- **Failures:** when a Dialog's `onConfirm` rejects, the Dialog stays open and shows `failureText`, a sentence in the user's language. The error's own message is written for developers and never shown. `onFailure` hears every rejection, where you report it, and may return a sentence to show instead.
- **Theme and feedback:** overlays wear the surrounding theme, or the host's `theme` when the screen in front wears another one. Their keys report to the surrounding `feedback` handler.
- **Knowing one is up:** `useOverlayUp()` is `true` while a Dialog or Menu is up anywhere, the same signal that holds toasts. Use it to wait before showing something of your own, such as a system prompt.
- **Closing everything:** `dismissOverlays()` closes every open and queued overlay as if the user had backed out. Call it when a session ends or a screen that owns a pending action goes away.

## Accessibility

- **Focus:** screen-reader focus moves to a Dialog's or Menu's title when it opens. Pass the control that opened it as `trigger`, and focus returns there when it closes.
- **Back:** Android Back cancels the Dialog or closes the Menu in front.
- **Toasts:** announced once when they first show. They never take screen-reader focus or block touches around their card.

## Platform differences

- **iOS:** the layer is a `FullWindowOverlay` from react-native-screens. In a native sheet, wrap the sheet's content in `SheetOrigin` so a Menu is placed next to its trigger: iOS measures inside a sheet from the sheet's top.
- **Android:** the layer is a transparent `Modal` that brings Back and focus with it. `SheetOrigin` is a plain view there.
- **Tests:** in Jest, mock `FullWindowOverlay` from `react-native-screens` with a plain `View`, since the test renderer has no native layer.

## Rules

- Mount exactly one `OverlayHost`, at the root, inside `ThemeProvider` and after the navigator.
- Never present a `Modal` or a navigator from inside an overlay.
- Navigate after `showDialog` resolves, not inside `onConfirm`: a screen presented while the Dialog is up lands above it.
- Write `failureText` in the user's language, as a neutral sentence.
- Pass the safe area through `insets` and `toastInsetTop`. TerraUI has no safe area of its own.
