import { QuotaKind } from '../quota'; /** The window event, and the two storage keys, one overlay instance owns. */ export interface AssistantOverlayKeys { /** Window event that opens, closes or toggles the overlay. */ toggleEvent: string; /** sessionStorage key for open/closed. */ openStorageKey: string; /** localStorage key for docked/floating. */ dockStorageKey: string; } /** * The keys for a product prefix. * * ★★ Byte-compatible with what the host apps already persist and dispatch: a * prefix of `hb` gives `hb:toggle-ai-assistant`, `hb:ai-panel:isOpen` and * `hb:ai-panel:docked`, exactly the strings those apps ship today. A host that * adopts this overlay with its existing prefix therefore keeps every user's * remembered dock choice and every dispatcher of its toggle event — no * migration, and nothing to re-seed. */ export declare function assistantOverlayKeys(prefix: string): AssistantOverlayKeys; /** * What a toggle event asks for: `detail.open` `true` opens, `false` closes, and * anything else — no detail, no `open`, a non-boolean, a plain `Event` — is a * toggle (`null`). * * ★★ `open: true` must NOT toggle. A "Get help" button dispatches it while the * panel may already be open; toggling there closes the panel — unmounting it, * and any turn in flight — at the moment the user asked for help. */ export declare function requestedAssistantOpenState(event: Event): boolean | null; /** The open state after a request: an explicit value wins, `null` toggles. */ export declare function nextAssistantOpenState(current: boolean, requested: boolean | null): boolean; /** The chord a user sees in the launcher's tooltip. */ export declare const ASSISTANT_TOGGLE_SHORTCUT_LABEL = "Ctrl+Shift+A"; /** * Ctrl+Shift+A, or Cmd+Shift+A on a Mac. * * ★ The key is lower-cased: with Shift held most layouts report `"A"`, but a * layout with Caps Lock on, or a synthetic event, reports `"a"`. Matching only * the upper case made the shortcut silently dead there. */ export declare function isAssistantToggleShortcut(event: Pick): boolean; /** * A dialog that owns its own Escape. * * ★★ `dialog[open]` as well as the roles: a native `` opened with * `showModal()` has an IMPLICIT dialog role, and `[role="dialog"]` is an * attribute selector that does not match it — so Escape dismissed the modal * AND closed the assistant underneath it. */ export declare const ASSISTANT_DIALOG_SELECTOR = "[role=\"dialog\"],[role=\"alertdialog\"],dialog[open]"; export type AssistantOverlayEscapeAction = 'close' | 'ignore'; /** * What the overlay does with a key press, given who else wants Escape. * * ★★★ Escape closes ONE thing. Two owners outrank the overlay, in this order: * * - an open dialog (the consent dialog, a product's native modal) handles its * own Escape; closing the assistant under it dismisses two things at once; * - the panel itself, when `assistantPanelOwnsEscape()` says so — one of its * full-surface overlays is showing and holds focus. The panel's listener is * on the same `document` node, so `stopPropagation` there cannot stop this * one; ownership has to be decided by STATE, not by listener order. * * Only when neither claims the key does the overlay close. */ export declare function assistantOverlayEscapeAction(input: { key: string; isOpen: boolean; dialogOpen: boolean; panelOwnsEscape: boolean; }): AssistantOverlayEscapeAction; /** * How far a bottom-anchored control must sit to clear the fixed chrome along * the bottom edge. * * ★★ The LARGER of the tab bar and the safe area, never their sum. The shell's * `MobileTabBar` publishes its measured height as `--mobile-tabbar-height`, and * that height already includes its own safe-area padding — so adding the safe * area again lifts the launcher a second home-indicator's height on a notched * phone. Where there is no tab bar the variable is 0px and the safe area wins. */ export declare const ASSISTANT_BOTTOM_CHROME_CLEARANCE = "max(var(--mobile-tabbar-height, 0px), var(--safe-bottom, 0px), env(safe-area-inset-bottom, 0px))"; /** * A CSS `bottom` value `inset` above whatever bottom chrome is showing. * * Exported for hosts that stack their own floating controls above the launcher * (a page-discussion button, say): lifting only the launcher slides it into * whatever sat above it. */ export declare function aboveAssistantBottomChrome(inset: string): string; /** Width of the docked side panel. Must match `sm:w-[440px]` below. */ export declare const ASSISTANT_DOCK_WIDTH_PX = 440; /** * CSS custom property on `` carrying the docked panel's width (`440px` * while docked and open on a desktop viewport, `0px` otherwise). A product's * own right-hand surface (a preview pane) pads by it to stay clear of the dock. */ export declare const ASSISTANT_DOCK_WIDTH_VAR = "--assistant-dock-width"; /** CSS custom property on the sheet carrying the docked panel's top offset. */ export declare const ASSISTANT_OVERLAY_TOP_VAR = "--assistant-overlay-top"; /** Default top offset for the docked panel: a 3.5rem (56px) shell header. */ export declare const ASSISTANT_OVERLAY_DEFAULT_TOP_PX = 56; /** * Where the layout switches from the phone sheet to the desktop window. * Must agree with the `sm:` prefix on every desktop class below. */ export declare const ASSISTANT_OVERLAY_DESKTOP_QUERY = "(min-width: 640px)"; /** The dock width actually taken from the page right now, in px. */ export declare function publishedAssistantDockWidth(input: { isOpen: boolean; docked: boolean; isDesktop: boolean; }): number; /** * Shared by every layout. On a phone: a full-width bottom sheet with a rounded * top edge. ★ No height here — see the two below. */ export declare const ASSISTANT_SHEET_BASE_CLASS: string; /** Phone: opens COMPACT, leaving the page visible above it. */ export declare const ASSISTANT_SHEET_COMPACT_CLASS = "h-[60vh] max-h-[60vh]"; /** Phone, expanded from the grab handle. */ export declare const ASSISTANT_SHEET_EXPANDED_CLASS = "h-[88vh] max-h-[88vh]"; /** Desktop floating window, rising from the launcher, clamped to the viewport. */ export declare const ASSISTANT_FLOATING_DESKTOP_CLASS: string; /** * Desktop docked side panel, from below the shell header to the bottom edge. * The top is a variable so a product with a different header height sets * `topOffsetPx` instead of forking the class. */ export declare const ASSISTANT_DOCKED_DESKTOP_CLASS: string; /** * The sheet's class for a layout. * * ★★ Both layout axes select a CLASS on one persistent element — never a mount. * The in-flight turn, draft attachments, microphone capture, TTS playback and * the voice session id all live in React state below it, so a conditional * mount or a changing `key` for dock or expand would reset every one of them. */ export declare function assistantOverlayClassName(input: { expanded: boolean; docked: boolean; }): string; export interface AssistantNavigateOptions { /** The product router's navigate, e.g. React Router's `useNavigate()`. */ navigate: (path: string) => void; /** * Paths the product renders WITHOUT the shell that hosts this overlay — auth * screens, invite acceptance, public portals. Pass the same predicate the * shell itself uses to decide, or the two will disagree. */ isShellLessTarget?: (path: string) => boolean; /** Is the desktop layout showing? */ isDesktop: () => boolean; /** Collapse the phone sheet to its compact height. */ collapseSheet: () => void; /** Open a path in a new tab. */ openInNewTab: (path: string) => void; } /** * Route a link the assistant put in a reply. * * The panel hands over a router-ready, same-origin PATH, so this is a plain * in-app route change: no reload, and the panel, the in-flight turn and any * voice session survive it. * * ★★ A shell-less destination opens in a NEW TAB and is never routed. The * overlay is mounted inside the shell; routing to a page rendered without the * shell unmounts the panel and destroys the conversation on every viewport. * * ★★ On a phone the sheet COLLAPSES, it does not close. The page the user asked * for renders beneath the sheet, so it steps aside — but closing unmounts the * panel, and collapsing is a class swap on the same node. On desktop the panel * sits beside the page and nothing moves. */ export declare function createAssistantNavigate(options: AssistantNavigateOptions): (path: string) => void; /** The quota wall a `:quota-exhausted` event names. */ export declare function assistantQuotaKindOf(event: Event): QuotaKind; /** A persisted `"1"`, read defensively: storage can be missing or throw. */ export declare function readAssistantOverlayFlag(storage: () => Pick | undefined, key: string): boolean; /** Persist a flag as `"1"`/`"0"`; an unavailable store keeps it in memory only. */ export declare function writeAssistantOverlayFlag(storage: () => Pick | undefined, key: string, value: boolean): void; //# sourceMappingURL=assistantOverlayState.d.ts.map