Summary
A sheet is a new shellframe navigation primitive that overlays the current screen but leaves a 1–2 row "back strip" visible at the top, showing the content beneath. Sheets are dismissible by pressing Esc, pressing Up from the topmost focused element (which shifts focus to the back strip), or (once click support exists) clicking anywhere in the back strip.
First consumer: fissible/shellql#12 — the "Open Database" form triggered by pressing `[o]` on the welcome screen.
Motivation
Modals (`shellframe_modal`) are appropriate for short confirmations and single-line prompts. Sheets are better suited for:
- Forms with multiple fields (e.g., network connection: host/port/user/db)
- Any prompt that benefits from visible context of the screen underneath
- Future deep-navigation flows (e.g. browse → filter → inspect)
The peek strip keeps the user oriented ("where did I come from?") without requiring a full screen transition.
Behaviour
┌──────────────────────────────────────┐
│ [back strip — 1–2 rows of underlay] │ ← shows previous screen content; Up/click → dismiss
├──────────────────────────────────────┤
│ │
│ Sheet content area │ ← full remaining height; no bottom constraint
│ (form, list, etc.) │
│ │
└──────────────────────────────────────┘
- Back strip height: 1–2 rows
- Dismissal: Esc anywhere in sheet; Up from topmost widget → focus moves to back strip → Enter/Esc/click dismisses
- No bottom constraint: sheet content fills from strip to screen bottom — suitable for longer forms
- Stacking: sheets can stack up to a depth of 2 above main chrome. Deeper sheets start one row lower so each layer's back strip is visible. A third push replaces the second sheet rather than adding a third layer.
API sketch
# Push a sheet over the current screen (analogous to shellframe_shell)
shellframe_sheet "_myapp" "OPEN_DB"
# Pop the topmost sheet (call from sheet's quit or back-strip action)
shellframe_sheet_pop
# Query current sheet depth (0 = no sheets active)
shellframe_sheet_depth
The sheet's render/key/action hooks follow the same naming convention as screens:
_myapp_OPEN_DB_render() { … }
_myapp_OPEN_DB_<region>_render() { … }
_myapp_OPEN_DB_<region>_on_key() { … }
_myapp_OPEN_DB_quit() { shellframe_sheet_pop; }
Implementation notes
- `shellframe_sheet` draws the back strip (saved terminal rows from the previous render) then runs the normal draw cycle for the sheet screen
- `_SHELLFRAME_SHEET_STACK` array tracks pushed sheet names + saved back-strip content
- When focus is at the topmost widget and Up is pressed, shift focus to a synthetic `backstrip` region; its action calls `shellframe_sheet_pop`
- `shellframe_sheet_pop` restores the full previous screen and resumes the parent input loop
Files
- `src/shell.sh` — sheet stack management, draw integration
- New: `src/sheet.sh` (or extend shell.sh directly)
Effort
M (~half day) | Deps: existing shell.sh focus model, panel, input widgets
Summary
A sheet is a new shellframe navigation primitive that overlays the current screen but leaves a 1–2 row "back strip" visible at the top, showing the content beneath. Sheets are dismissible by pressing Esc, pressing Up from the topmost focused element (which shifts focus to the back strip), or (once click support exists) clicking anywhere in the back strip.
First consumer: fissible/shellql#12 — the "Open Database" form triggered by pressing `[o]` on the welcome screen.
Motivation
Modals (`shellframe_modal`) are appropriate for short confirmations and single-line prompts. Sheets are better suited for:
The peek strip keeps the user oriented ("where did I come from?") without requiring a full screen transition.
Behaviour
API sketch
The sheet's render/key/action hooks follow the same naming convention as screens:
Implementation notes
Files
Effort
M (~half day) | Deps: existing shell.sh focus model, panel, input widgets