import type { VendoTheme } from "../../core/apps/index.js";
import { type ComponentType, type ReactNode } from "react";
import { type VendoDiscoverability, type VendoGreeting } from "./discoverability.js";
import { type VendoThreadProps } from "./thread/index.js";
/** F12 (ENG-388) — the launcher's viewport corners. */
export type VendoLauncherPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
export interface VendoOverlayProps {
/** Controlled open state — pair with `onOpenChange`. Omit for uncontrolled. */
open?: boolean;
/** Initial state in uncontrolled mode (default `false`). */
defaultOpen?: boolean;
/** Fires for every open/close request: launcher click, close button, Escape, scrim click, or programmatic toggles. */
onOpenChange?(open: boolean): void;
/**
* Built-in launcher placement and content. The default is `"none"`: a bare
* `` renders NO pill, and the panel opens programmatically
* — `open`/`onOpenChange`, the `useVendoOverlay` hook, `VendoTrigger`, the
* palette, or a slot.
*
* Opt the pill in with a corner string or the object form. `launcher={{}}`
* is the plain pill: a fixed pill in the corner carrying the accent-circle
* mark and a WHITE-LABEL text — "AI agent", never a product name.
* `position` picks the corner (default `"bottom-right"`), `label` accepts
* any host string (`null` collapses the pill to a blob-only orb), `icon`
* swaps the blob for a host element, and `offset` nudges the whole launcher
* cluster (pill, whisper, toast) inward from its corner when the host's own
* UI already lives there (F12, ENG-388).
*/
launcher?: VendoLauncherPosition | "none" | {
position?: VendoLauncherPosition;
/** Pill text. Default "AI agent"; `null` renders the blob-only orb. */
label?: string | null;
/** Replaces the circle mark (a host logo, custom glyph, …). */
icon?: ReactNode;
/** Extra pixels pushed inward from the anchored corner: `x` from the
* anchored side, `y` from the anchored edge. Safe-area insets still
* apply on top. */
offset?: {
x?: number;
y?: number;
};
};
/**
* Change to discard the current conversation and start a fresh thread
* (ENG-221). `useVendoOverlay().newConversation()` drives this for you;
* hosts managing their own state can bump any number/string. The panel's
* built-in new-conversation button works with or without this prop.
*/
conversationKey?: string | number;
/**
* The one sanctioned component-injection point: a thread component the panel
* renders in place of the built-in `VendoThread`. The overlay stays the
* positioning shell — portal, scrim, focus, mobile sheet — while a custom
* thread supplies the conversation pixels. It receives `VendoThreadProps`
* (all optional), so a plain zero-prop component works too.
*/
thread?: ComponentType;
/**
* The discoverability dial (ui-usage-dx §6), overriding the provider's.
* `"default"` keeps the fire-once whisper on the launcher pill (and the
* thread's greeting-as-tutorial); `"quiet"` turns both off. Nothing here
* ever fires twice for the same user — the whisper marks itself seen the
* moment it first renders.
*/
discoverability?: VendoDiscoverability;
/**
* Greeting-as-tutorial content for the thread's one-time first message
* (intro + prompt chips — the `.vendo/greeting.json` shape), overriding the
* provider's `greeting`.
*/
greeting?: VendoGreeting;
/**
* This surface's own brand tokens, merged group by group over the provider's
* resolved theme — the same merge `VendoProvider` does over
* `defaultVendoTheme`, so with no provider above this merges over the
* defaults. The panel portals to `` and the approval modal portals
* again from inside it; both carry these tokens.
*
* FRAME ONLY: it styles Vendo's own chrome — launcher, panel, thread,
* composer. A generated view mounted in the conversation keeps the PROVIDER
* theme, whether it is iframe-served (themed over the app transport) or
* rendered natively: the tree surface restates the provider tokens on its
* own root, so the local ones do not cascade in.
*/
theme?: Partial;
/**
* Where the panel sits while open.
*
* `"center"` (the default) is the centered modal box: scrim, body
* scroll-lock, inert background and focus trap. It stays the default so
* upgrading never changes an existing host's behavior.
*
* `"dock"` is the opt-in DevTools posture: a full-height side panel against
* the right edge, with the host page REFLOWED beside it. It is deliberately
* NON-modal — none of those four containments — because the page is the
* thing being reshaped and has to stay visible and clickable while the panel
* is open. Below the mobile breakpoint both collapse to the full-bleed
* takeover, which owns small screens either way.
*/
placement?: "dock" | "center";
/** Docked panel width in CSS px (default 420) — also the amount the host
* page reflows by, so the two can never disagree. */
dockWidth?: number;
/**
* The one line the panel shows a visitor the wire refused for missing
* identity (H2-E / #1372) — host-brandable, defaulting to
* "Sign in to use the agent." The launcher still renders (nothing about
* wire health hides it); only the panel content changes, and the server's
* developer-facing resolver message never reaches this surface. The panel
* returns to the conversation on `vendo:identity-changed` or the first
* successful wire read.
*/
signedOutNotice?: string;
}
/** 08-ui §4 — floating modal launcher with focus containment and restoration.
* Supported entry API (ENG-220): opt-in positioned launcher, controlled +
* uncontrolled programmatic open/close, panel portaled to document.body with
* body scroll-lock and an inert background while open. */
export declare function VendoOverlay({ open: openProp, defaultOpen, onOpenChange, launcher, conversationKey, thread: Thread, discoverability, greeting, theme: themeOverride, placement, dockWidth, signedOutNotice, }?: VendoOverlayProps): import("react").JSX.Element;