Skip to content

ScreenStack router for push/pop navigation#87

Merged
meszmate merged 1 commit intomainfrom
feature/screen-stack
Apr 23, 2026
Merged

ScreenStack router for push/pop navigation#87
meszmate merged 1 commit intomainfrom
feature/screen-stack

Conversation

@meszmate
Copy link
Copy Markdown
Owner

Summary

Adds a screen router so apps can push/pop self-contained screens the way a browser navigates pages. Currently every nontrivial Bubble Tea–style app hand-rolls this — now it's a first-class primitive.

How it differs from SubProgram

`SubProgram` is a static-typed wrapper for one specific child model. `ScreenStack` is a runtime-typed stack of heterogeneous screens — login screen, home screen, modal dialog, command palette can all live in the same stack despite being unrelated types.

API

A `Screen` is a thin vtable: `update(key) -> Action`, `view` returning a string, plus optional `deinit`, `on_enter`, `on_suspend`, `on_resume` lifecycle hooks. Actions returned from `update` are: `none`, `pop`, `push(screen)`, `replace(screen)`, `quit`.

`ScreenStack` exposes `push`, `pop`, `replace`, `top`, `depth`, `handleKey`, `view`. Modal screens are rendered centered on top of the screen below; non-modal screens hide whatever's beneath.

Usage

```zig
var stack = zz.ScreenStack.init(allocator);
defer stack.deinit();
try stack.push(login_screen);
// In top-level update:
switch (try stack.handleKey(&ctx, key)) {
.quit => return .quit,
else => {},
}
// In top-level view:
return try stack.view(&ctx, allocator);
```

Test plan

  • `zig build test` — added 4 tests covering push/pop, key-driven pop action, quit propagation, and modal overlay composition

Type-erased stack of screens (each with its own state, key handler, and
view) wired together via a small vtable interface. Distinct from
SubProgram (static-typed wrapper for one child model): a ScreenStack
holds heterogeneous screens at runtime and supports browser-style
push/pop/replace navigation.

Screens marked modal are layered on top of the previous screen
(centered) — useful for confirm dialogs and command palettes — while
non-modal screens hide whatever's beneath. Lifecycle hooks
on_enter/on_suspend/on_resume let screens manage per-presentation
state.
@meszmate meszmate merged commit 836faeb into main Apr 23, 2026
9 checks passed
@meszmate meszmate deleted the feature/screen-stack branch April 24, 2026 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant