import { type ResolvedBindings } from "./keymap.js"; export type Tone = "success" | "warning" | "error" | "info" | "muted"; export interface ConfirmPromptOptions { title: string; message: string; confirmLabel?: string; cancelLabel?: string; destructive?: boolean; } export interface Row { id: string; title: string; subtitle?: string; badge?: { text: string; tone?: Tone; }; group?: string; } export interface DetailItem { id: string; title?: string; subtitle?: string; badge?: { text: string; tone?: Tone; }; render: (ctx: DetailCtx) => string | Promise; renderedContent?: string; } export interface Detail { items: (row: Row, ctx: DetailCtx) => Promise; actions?: Action[]; } export interface DetailCtx { width: number; height: number; signal: AbortSignal; row: Row; /** Re-run detail.items for the focused row and repaint the preview pane. */ reloadDetail?: () => void; } export interface Action { id: string; label: string | (() => string); key?: string | string[]; accelerator?: string; predicate?: (ctx: ActionContext) => boolean; visible?: (row: Row) => boolean; handler: (ctx: ActionContext) => void | Promise; destructive?: boolean; primary?: boolean; showInFooter?: boolean; } export interface ActionContext { row: Row; rows: Row[]; item?: DetailItem; filter: string; refresh: () => Promise; /** Re-run detail.items for the focused row and repaint the preview pane. */ reloadDetail: () => void; suspendAnd: (fn: () => Promise) => Promise; openModal: (content: { title: string; content: string; }) => void; toast: (msg: string, tone?: Tone) => void; confirm: (prompt: string | ConfirmPromptOptions) => Promise; promptText: (options: { title: string; label: string; initialValue?: string; placeholder?: string; }) => Promise; exit: (after?: () => void | Promise) => void; activePane?: PaneRuntimeState; inactivePane?: PaneRuntimeState; } export interface ListPaneConfig { id: string; kind: "list"; title: string; rows: () => Promise; emptyHint?: string; multiSelect?: boolean; } export interface DetailPaneConfig { id: string; kind: "detail"; title: string; titleForRow?: (row: Row | undefined) => string; render: (row: Row | undefined, ctx: DetailCtx) => string | Promise; } export type PaneConfig = ListPaneConfig | DetailPaneConfig; export interface PaneRuntimeState { id: string; title: string; rows: Row[]; cursor: number; selected: Set; filter: string; } export interface ReorderContext { movedId: string; refresh: () => Promise; toast: (msg: string, tone?: Tone) => void; } export interface ExplorerConfig { title: string; panes?: PaneConfig[]; rows?: () => Promise; refresh?: () => void | Promise; detail?: Detail; actions: Action[]; reorder?: { onReorder: (orderedIds: string[], ctx?: ReorderContext) => void | Promise; }; multiSelect?: boolean; keybindOverrides?: Record; emptyHint?: string; initialFilter?: string; /** Synchronous first paint rows; still refreshed via `rows()` after start. */ initialRows?: Row[]; /** Disable terminal mouse reporting when native text selection is more useful than wheel input. */ mouse?: boolean; } export type NormalizedExplorerConfig = ExplorerConfig & { rows: () => Promise; detail: Detail; }; export declare function normalizeExplorerConfig(config: ExplorerConfig): NormalizedExplorerConfig; export declare const REGION_HEADER: number; export declare const REGION_LIST: number; export declare const REGION_DETAIL: number; export declare const REGION_FOOTER: number; export declare const REGION_MODAL: number; export declare const REGION_TOAST: number; export declare const REGION_ALL: number; export type Dirty = number; export type ExplorerLayoutMode = "wide" | "medium" | "narrow-vertical" | "narrow-list-only" | "too-narrow"; export interface ExplorerSize { cols: number; rows: number; } export interface ExplorerState { title: string; emptyHint: string; rows: Row[]; rowsLoading: boolean; filtered: number[]; matchPositions: Map; cursor: number; filter: string; filterFocused: boolean; focused: "list" | "detail"; detail: { rowId: string | null; items: DetailItem[] | null; allItems?: DetailItem[] | null; filter?: string; cursor: number; scroll: number; token: number; loading: boolean; }; selected: Set; multiSelect: boolean; modal: null | { kind: "help"; } | { kind: "confirm"; title: string; message: string; confirmLabel: string; cancelLabel: string; destructive: boolean; resolver: (ok: boolean) => void; action?: Action; rows?: Row[]; } | { kind: "input"; title: string; label: string; value: string; placeholder?: string; resolver: (value: string | null) => void; } | { kind: "palette"; query: string; cursor: number; } | { kind: "content"; title: string; content: string; scroll: number; }; toast: { message: string; tone: Tone; expiresAt: number; } | null; dirty: Dirty; size: ExplorerSize; layout: ExplorerLayoutMode; bindings: ResolvedBindings; actionState: Map; suspended: boolean; paneDefinitions: Array<{ id: string; title: string; kind: "list" | "detail"; titleForRow?: (row: Row | undefined) => string; }>; } export interface ActionStateEntry { available: boolean; label: string; running?: boolean; action?: Action; source?: "row" | "detail" | "both"; } export declare function createInitialState(config: ExplorerConfig, size: ExplorerSize): ExplorerState; export declare function resolveExplorerLayoutMode(cols: number, rows?: number): ExplorerLayoutMode;