export type SessionFocusTarget = "row" | "actions"; export type SessionRowRevealIntent = { current: string | null; }; export declare const FOCUS_SESSION_COMPOSER_EVENT = "opengeni:focus-session-composer"; /** * Who asked for the composer: a click on the chat's sidebar row, or a keyboard * jump (the command menu, Control+Tab). Opening or reloading a chat with * nothing focused asks too, without an intent ("load"). */ export type SessionComposerFocusSource = "rail" | "keyboard" | "load"; export type SessionComposerFocusIntent = { workspaceId: string; sessionId: string; nonce: number; source: SessionComposerFocusSource; }; /** * Record one explicit desktop navigation intent (a sidebar row click or a * keyboard jump) before route navigation. Polling and background state changes * never call this seam, so they cannot acquire composer focus. */ export declare function requestSessionComposerFocus(events: EventTarget, workspaceId: string, sessionId: string, source?: Exclude): void; /** Consume only the exact destination's one-shot rail-click intent. */ export declare function consumeSessionComposerFocusIntent(events: EventTarget, workspaceId: string, sessionId: string): SessionComposerFocusIntent | null; /** Test/teardown seam. Production callers should consume rather than clear. */ export declare function clearSessionComposerFocusIntent(): void; /** * Whether the composer may take focus now. Any open dialog wins. A keyboard * jump replaces whatever the previous chat had focused. A rail click replaces * only focus that still belongs to that click (its own row). Opening or * reloading a chat takes focus only when nothing is focused. */ export declare function shouldFocusSessionComposer(active: HTMLElement | null, sessionId: string, body: HTMLElement | null, dialogOpen: boolean, source?: SessionComposerFocusSource): boolean; /** * Focus the chat's composer once it can take focus: the command menu may still * be closing and the composer may still be loading its draft (disabled). Gives * up when focus moves elsewhere in the meantime or after a few seconds. * Returns a cancel function. */ export declare function focusSessionComposerWhenReady(input: { textarea: () => HTMLTextAreaElement | null | undefined; sessionId: string; source: SessionComposerFocusSource; doc?: Document; now?: () => number; requestFrame?: (callback: () => void) => number; cancelFrame?: (handle: number) => void; }): () => void; export declare function sessionComposerFocusIntentIsEligible(input: { viewportWidth: number; coarsePointer: boolean; terminal: boolean; requiresAction: boolean; pendingHumanInput: boolean; pendingApproval: boolean; }): boolean; /** Reader-owned rail movement supersedes an unfulfilled programmatic reveal. */ export declare function cancelSessionRowRevealIntent(intent: SessionRowRevealIntent): void; /** * Reveal one explicitly requested row and consume the request. Re-running this * during polling, pagination, or title/status churn is a no-op until a caller * records a new route/"Show path" intent. */ export declare function consumeSessionRowRevealIntent(root: HTMLElement, intent: SessionRowRevealIntent): HTMLElement | null; /** * Boundary navigation is a visual no-op when the requested index is already * focused. It must not leave an intent behind for a later list refresh to * interpret as a request to move DOM focus back to the row. */ export declare function shouldRecordSessionRowFocusIntent(requestedIndex: number | null, currentIndex: number): boolean; /** * Roving focus may move real DOM focus only for an explicit keyboard-navigation * intent. A pin or project move can reorder/remount the same row while * preserving its focus index; that derived change must not steal focus from a * restored row actions trigger. */ export declare function shouldMoveSessionRowFocus(intentSessionId: string | null, renderedSessionId: string | null): boolean; export declare function sessionFocusAttribute(target: SessionFocusTarget): "data-session-row" | "data-session-actions"; /** * Decide whether a group-remount focus restore may replace the active element. * An unrelated input, button, or menu is never displaced; only focus lost to * the operation's own remount/ Radix close path is eligible. */ export declare function shouldRestoreSessionFocus(active: HTMLElement | null, destination: HTMLElement, sessionId: string, body: HTMLElement | null): boolean; /** Completes only the focus obligation represented by this committed layout. */ export declare function createSessionFocusCompletion(pending: { current: { operation: number; settled: boolean; } | null; }, restore: () => void): () => void;