import type { ToolbarMode } from '../annotate/toolbar.js'; import type { TargetRect } from '../types.js'; export type ModeKind = 'idle' | 'annotating' | 'recording' | 'drawing' | 'popup' | 'clarifying' | 'submitting'; export interface NotePopupOptions { x: number; y: number; targetName: string; targetRect?: TargetRect; } /** * The controller-side verbs a mode may perform. Each verb owns one concrete * mount, unmount, or hand-off; the states own which verbs run for which input * in which mode. Kept as an interface (implemented by WidgetController) so the * coupling between the machine and its resources is written down in one place. */ export interface ModeHost { transitionTo(next: ModeState): void; exitAll(): void; dismissFrustrationPrompt(): void; /** True once the annotation toolbar is mounted — the flow chrome exists. */ hasAnnotationChrome(): boolean; /** First entry into markup: font warmup, toolbar, drawing surface, mobile strip. */ mountAnnotationChrome(): void; ensureSession(): void; destroySession(): void; clearCurrentAnnotation(): void; teardownDrawBar(): void; destroyRecordingManager(): void; startRecorder(): void; stopRecordingIntoNote(): void; cancelDraw(): void; mountDrawBar(): void; mountDrawSheet(): void; refreshDrawBar(): void; mountNotePopup(opts: NotePopupOptions): void; /** Abandon the note popup without ending the flow: surface, scrim and scroll lock come down, annotating resumes. */ dismissNotePopup(): void; /** Dismiss the success card from the previous submission. */ dismissSuccess(): void; revertToolbarDuringClarify(): void; releaseClarifyUi(): void; } /** * One object per widget mode. The controller holds a single `state` reference * and delegates every mode-dependent input here; transitions run through * `transitionTo(next)`, which calls the outgoing state's exit() before the * incoming state's enter(). * * enter() mounts what the mode itself needs. exit() is deliberately thin: the * toolbar and the annotation session span the whole flow (annotating through * clarifying), and several out-edges hand a resource to the next mode instead * of releasing it — the note popup's element becomes the clarify card, a * stopped recording becomes the submit payload. Those edges release or hand * off through their own named paths (cancelDraw, the submit teardown, exitAll), * and exitAll remains the universal release every abandon route ends in. */ export interface ModeState { readonly kind: ModeKind; /** Whether the docked launcher renders lit while this mode is active. */ readonly launcherLit: boolean; /** Whether a frustration signal may surface its prompt in this mode. */ readonly acceptsFrustrationPrompt: boolean; enter(): void; exit(): void; /** Public API open(). Only idle acts; while open it is an idempotent no-op. */ handleOpen(): void; handleClose(): void; handleEscape(event: KeyboardEvent): void; handleTabClick(): void; handleToolbarModeChange(mode: ToolbarMode): void; /** A stroke landed on the annotation overlay. */ handleDrawStroke(): void; } declare abstract class BaseModeState implements ModeState { protected host: ModeHost; abstract readonly kind: ModeKind; readonly launcherLit: boolean; readonly acceptsFrustrationPrompt: boolean; constructor(host: ModeHost); enter(): void; exit(): void; handleOpen(): void; handleClose(): void; handleEscape(_event: KeyboardEvent): void; handleTabClick(): void; handleToolbarModeChange(_mode: ToolbarMode): void; handleDrawStroke(): void; } export declare class IdleState extends BaseModeState { readonly kind = "idle"; readonly launcherLit = false; readonly acceptsFrustrationPrompt = true; handleOpen(): void; handleClose(): void; handleTabClick(): void; } export declare class AnnotatingState extends BaseModeState { readonly kind = "annotating"; enter(): void; handleEscape(event: KeyboardEvent): void; handleToolbarModeChange(mode: ToolbarMode): void; handleDrawStroke(): void; } export declare class RecordingState extends BaseModeState { readonly kind = "recording"; enter(): void; handleEscape(event: KeyboardEvent): void; handleToolbarModeChange(mode: ToolbarMode): void; } export declare class DrawingState extends BaseModeState { private surface; readonly kind = "drawing"; constructor(host: ModeHost, surface: 'bar' | 'sheet'); enter(): void; handleEscape(event: KeyboardEvent): void; handleToolbarModeChange(mode: ToolbarMode): void; handleDrawStroke(): void; } export declare class PopupState extends BaseModeState { private opts; readonly kind = "popup"; constructor(host: ModeHost, opts: NotePopupOptions); enter(): void; handleEscape(event: KeyboardEvent): void; handleToolbarModeChange(mode: ToolbarMode): void; } /** * A question is open inside the chat card. The card is already mounted and * stays put, so entering mounts nothing — what changes is that the submission * is now on the server, which is why Escape stops being a cancel here. */ export declare class ChatClarifyingState extends BaseModeState { readonly kind = "clarifying"; handleToolbarModeChange(_mode: ToolbarMode): void; } export declare class SubmittingState extends BaseModeState { readonly kind = "submitting"; readonly launcherLit = false; enter(): void; handleTabClick(): void; } export {}; //# sourceMappingURL=mode-states.d.ts.map