import type { ReactNode } from "react"; import type { CommandSurfaceRole, Mode } from "@tooee/commands"; export type OverlayId = string; export type OverlayCloseReason = "close" | "escape" | "replaced" | "unmounted"; export type OverlayRole = CommandSurfaceRole; export interface OverlayOpenOptions { /** Mode to set while overlay is active (default: "insert"). null = don't change mode. */ mode?: Mode | null; /** Restore previous mode on close (default: true) */ restoreMode?: boolean; /** Allow Escape to close this overlay (default: true) */ dismissOnEscape?: boolean; /** * Mount the overlay as an owned command surface: it gets a local command * registry and local mode, and (when `role` is "modal") suspends parent app * command dispatch while topmost. When set, the overlay does not mutate the * host app's global mode. Overlay commands are registered with `useCommand` * inside the overlay's render, exactly like a standalone app. */ ownCommands?: boolean; /** * Interaction role for an owned command surface (default "modal"). Only * meaningful when `ownCommands` is true. */ role?: OverlayRole; /** Initial local mode for an owned command surface (default "cursor"). */ surfaceMode?: Mode; /** Lifecycle callback */ onClose?: (reason: OverlayCloseReason) => void; } /** * An overlay payload change. The two cases are explicit because an overlay * payload may itself be a function: `{ kind: "value" }` always replaces the * payload, `{ kind: "updater" }` always derives it from the previous one. A * `typeof next === "function"` check cannot tell those apart, so the caller * chooses. Use the `overlayValue` / `overlayUpdater` helpers. */ export type OverlayUpdate = { kind: "value"; value: TPayload; } | { kind: "updater"; update: (previous: TPayload) => TPayload; }; /** Replace an overlay payload outright (safe even when the payload is a function). */ export declare const overlayValue: (value: TPayload) => OverlayUpdate; /** Derive the next overlay payload from the previous one. */ export declare const overlayUpdater: (update: (previous: TPayload) => TPayload) => OverlayUpdate; export interface OverlayRenderArgs { id: OverlayId; payload: TPayload; isTop: boolean; close: (reason?: OverlayCloseReason) => void; update: (next: OverlayUpdate) => void; } export type OverlayRenderer = (args: OverlayRenderArgs) => ReactNode; export interface OverlayHandle { id: OverlayId; close: (reason?: OverlayCloseReason) => void; update: (next: OverlayUpdate) => void; } export interface OverlayController { open: (id: OverlayId, render: OverlayRenderer, payload: TPayload, options?: OverlayOpenOptions) => OverlayHandle; update: (id: OverlayId, next: OverlayUpdate) => void; show: (id: OverlayId, content: ReactNode, options?: OverlayOpenOptions) => void; hide: (id: OverlayId) => void; closeTop: (reason?: OverlayCloseReason) => void; isOpen: (id: OverlayId) => boolean; topId: OverlayId | null; } export interface OverlayState { current: ReactNode | null; hasOverlay: boolean; /** * True when any overlay other than a passive owned surface is open. Passive * surfaces (e.g. the which-key hint) render for visuals only and never own * input, so they don't count. Use this for guards that should stand down * while a modal overlay is up but keep working under passive hints. */ hasModalOverlay: boolean; stack: OverlayId[]; } export interface OverlayContextValue { show: (id: string, content: ReactNode, options?: OverlayOpenOptions) => void; hide: (id: string) => void; current: ReactNode | null; hasOverlay: boolean; } export declare const OverlayControllerContext: import("react").Context; export declare const OverlayStateContext: import("react").Context; export declare const OverlayContext: import("react").Context; export declare const useOverlay: () => OverlayController; export declare const useOverlayState: () => OverlayState; export declare const useHasOverlay: () => boolean; export declare const useHasModalOverlay: () => boolean; export declare const useCurrentOverlay: () => ReactNode | null; //# sourceMappingURL=overlay-context.d.ts.map