/** * ViewHistory — lightweight in-app navigation stack for rApps. * * Each rApp with hierarchical views instantiates one, calls push() * on forward navigation, and back() from the back button. Replaces * hardcoded data-back targets with a proper history stack. */ export interface ViewEntry { view: V; context?: Record; } const MAX_DEPTH = 20; export class ViewHistory { private stack: ViewEntry[] = []; private root: V; constructor(rootView: V) { this.root = rootView; } /** Record a forward navigation. Skips if top of stack is same view+context. */ push(view: V, context?: Record): void { const top = this.stack[this.stack.length - 1]; if (top && top.view === view) return; // skip duplicate this.stack.push({ view, context }); if (this.stack.length > MAX_DEPTH) this.stack.shift(); } /** Pop and return the previous entry, or null if at root. */ back(): ViewEntry | null { if (this.stack.length <= 1) { this.stack = []; return { view: this.root }; } this.stack.pop(); // remove current return this.stack[this.stack.length - 1] ?? { view: this.root }; } /** True when there's history to go back to. */ get canGoBack(): boolean { return this.stack.length > 1; } /** Peek at the previous entry without popping. */ peekBack(): ViewEntry | null { if (this.stack.length <= 1) return { view: this.root }; return this.stack[this.stack.length - 2] ?? null; } /** Clear the stack and reset to a root view (e.g. on space switch). */ reset(rootView?: V): void { if (rootView !== undefined) this.root = rootView; this.stack = []; } }