Update status bar shortcut documentation

This commit is contained in:
phranck
2026-03-10 16:34:04 +01:00
parent 400cc2ba00
commit 02719e6c98
4 changed files with 138 additions and 27 deletions
@@ -255,6 +255,10 @@ extension View {
/// When this view is rendered, the specified items will be displayed
/// in the status bar. This replaces any existing global items.
///
/// If a user item uses the same shortcut string as a system item
/// (for example `q`), the user item wins in both display and event
/// handling for that view context.
///
/// # Example
///
/// ```swift
@@ -283,6 +287,10 @@ extension View {
/// items using the `.merge` strategy (default). Use
/// ``statusBarItems(_:_:)`` to specify a different strategy.
///
/// A user-defined item can intentionally override a system shortcut such
/// as `q`. When the item has an action, it intercepts the key before the
/// built-in quit binding runs.
///
/// # Example
///
/// ```swift
@@ -309,6 +317,9 @@ extension View {
/// Child wins on shortcut conflict.
/// - **`.replace`**: Items replace all parent items (cascade barrier).
///
/// Shortcut conflicts are resolved in favor of the most local user item.
/// This also applies to system shortcuts such as `q`.
///
/// # Example
///
/// ```swift
@@ -68,6 +68,9 @@ public extension View {
/// .statusBarSystemItems(theme: true, appearance: true)
/// ```
///
/// To hide the status bar completely, combine this with no registered
/// user items and set ``StatusBarState/showSystemItems`` to `false`.
///
/// - Parameters:
/// - theme: Whether to show the theme switcher (`t theme`). Default is `false`.
/// - appearance: Whether to show the appearance switcher (`a appearance`). Default is `false`.
@@ -186,6 +186,39 @@ Dialog(title: "Confirm") {
}
```
### Changing the built-in quit key
The default quit binding is configurable through ``StatusBarState/quitShortcut``:
```swift
@Environment(\.statusBar) private var statusBar
statusBar.quitShortcut = .escape
statusBar.quitShortcut = .ctrlQ
statusBar.quitShortcut = QuitShortcut(
key: .f12,
shortcutSymbol: Shortcut.f12,
label: "exit"
)
```
This changes both the Layer 4 quit binding and the displayed system item.
### Overriding `q` in a local view context
A user-defined status bar item with shortcut `q` and an action intercepts the key before the default quit binding runs:
```swift
EditorView()
.statusBarItems {
StatusBarItem(shortcut: "q", label: "close") {
dismissEditor()
}
}
```
This is the correct way to repurpose `q` for a specific screen, dialog, or focus section. The matching user item handles the event in Layer 1, so Layer 4's built-in quit binding is never reached.
## Status Bar Shortcuts
The status bar displays available shortcuts to the user. Use the ``Shortcut`` namespace for consistent, platform-standard symbols:
@@ -304,6 +337,8 @@ statusBar.showThemeItem = false // Hide only theme cycling
statusBar.showAppearanceItem = false // Hide only appearance cycling
```
When all system items are hidden and there are no active user items, the status bar is hidden completely.
## Topics
### Input Types
@@ -4,7 +4,9 @@ Configure the shortcut bar at the bottom of the terminal.
## Overview
The status bar is a persistent row at the bottom of the terminal that shows keyboard shortcuts and contextual information. It is always visible and updates every frame.
The status bar is a row at the bottom of the terminal that shows keyboard shortcuts and contextual information. It updates every frame while it has active items.
The status bar is hidden automatically when there are no active user items and no visible system items.
TUIkit provides two status bar styles: ``StatusBarStyle/compact`` (single-line, shortcuts only) and ``StatusBarStyle/bordered`` (bordered with title support).
@@ -25,10 +27,10 @@ VStack {
Text("My App")
}
.statusBarItems {
StatusBarItem(.character("n"), label: "New") {
StatusBarItem(shortcut: "n", label: "new") {
// handle "n" key press
}
StatusBarItem(.character("d"), label: "Delete") {
StatusBarItem(shortcut: "d", label: "delete") {
// handle "d" key press
}
}
@@ -36,37 +38,43 @@ VStack {
Items are registered per frame during rendering. When a view is removed from the tree, its items automatically disappear from the status bar.
## The Shortcut Enum
## Shortcut Display Symbols
``Shortcut`` defines the key trigger for a status bar item:
Use ``Shortcut`` to keep displayed shortcut symbols consistent:
| Shortcut | Display | Description |
| Constant | Display | Description |
|----------|---------|-------------|
| `.character("q")` | `q` | A single character key |
| `.tab` | `` | Tab key |
| `.enter` | `` | Enter / Return |
| `.escape` | `` | Escape key |
| `.backspace` | `` | Backspace / Delete |
| `.arrows` | `` | Arrow keys |
| `.arrowsHorizontal` | `←→` | Left / Right arrows |
| `.arrowsVertical` | `↑↓` | Up / Down arrows |
| `Shortcut.quit` | `q` | Default quit display |
| `Shortcut.enter` | `` | Enter / Return |
| `Shortcut.escape` | `` | Escape |
| `Shortcut.tab` | `` | Tab |
| `Shortcut.arrowUp` | `` | Arrow up |
| `Shortcut.arrowDown` | `` | Arrow down |
| `Shortcut.arrowsUpDown` | `↑↓` | Vertical navigation |
| `Shortcut.ctrl("q")` | `⌃q` | Ctrl+Q display |
`Shortcut` defines how the item is displayed. If you do not pass `key:`, `StatusBarItem` derives a trigger key from the shortcut string where possible.
## Context Stack
Status bar items use a **context stack**. When a dialog or menu opens, it can push its own items onto the stack. The status bar always shows the topmost context:
Status bar items use a **context stack**. Context-specific items can temporarily replace global items, for example while a dialog is visible:
```swift
// Push a new context (e.g. when opening a dialog)
statusBar.pushContext()
// Add items to the new context
statusBar.addItem(StatusBarItem(.escape, label: "Close") { ... })
// Pop the context when the dialog closes
statusBar.popContext()
Dialog(title: "Confirm") {
Text("Delete file?")
} footer: {
ButtonRow {
Button("Delete") { delete() }
Button("Cancel") { cancel() }
}
}
.statusBarItems(context: "confirm-dialog") {
StatusBarItem(shortcut: "y", label: "yes") { delete() }
StatusBarItem(shortcut: "n", label: "no") { cancel() }
}
```
This means the main view's shortcuts are hidden while a modal is active, and automatically restored when it closes.
The topmost context replaces global user items in the display. System items remain visible unless a user item uses the same shortcut string.
## System Items
@@ -74,11 +82,65 @@ TUIkit registers built-in system items automatically:
| Key | Label | Action |
|-----|-------|--------|
| `q` / `Ctrl+C` | Quit | Exit the application |
| `p` | Palette | Cycle to next color palette |
| `q` | Quit | Exit the application |
| `a` | Appearance | Cycle to next border appearance |
| `t` | Theme | Cycle to next color theme |
These appear on the right side of the status bar. You can configure quit behavior via ``QuitBehavior``.
These appear on the right side of the status bar. Only `q quit` is shown by default. Enable `a appearance` and `t theme` with the ``View/statusBarSystemItems(theme:appearance:)`` modifier.
### Overriding `q quit`
A user-defined status bar item with shortcut `q` overrides the built-in quit binding for that view context:
```swift
EditorView()
.statusBarItems {
StatusBarItem(shortcut: "q", label: "close") {
closeEditor()
}
}
```
This works because status bar items with actions are handled before the default quit binding. The built-in `q quit` system item is also removed from the display when a user item uses the same shortcut string.
### Changing the global quit shortcut
Change the built-in quit key through ``StatusBarState/quitShortcut``:
```swift
@main
struct MyApp: App {
@Environment(\.statusBar) private var statusBar
var body: some Scene {
WindowGroup {
ContentView()
}
.task {
statusBar.quitShortcut = .escape
}
}
}
```
Available presets include ``QuitShortcut/q``, ``QuitShortcut/escape``, ``QuitShortcut/ctrlQ``, and ``QuitShortcut/ctrlC``. You can also create a fully custom ``QuitShortcut``.
### Hiding the status bar completely
Hide all system items and do not register any user items:
```swift
ContentView()
.statusBarSystemItems(theme: false, appearance: false)
```
```swift
@Environment(\.statusBar) private var statusBar
statusBar.showSystemItems = false
```
When there are no active items left, the status bar height becomes zero and it is not rendered.
## Status Bar Styles