Move focus between panes
You'll split the task list into a list pane and a detail pane, move between them with Tab and Shift+Tab and give each pane its own keys. It starts from the app you built in 640.
Before you start
Install from crates.io. You need no Node and no package manager.
cargo install snapfire_compiler
cargo install snapfire_fsr_cli
fsr --version
Every command and screenshot on this page was captured with fsr 0.x.
Focus in Ink#
useFocus makes a component focusable and tells it whether it has the focus. Tab moves the focus to the next focusable component in the order they render and Shift+Tab moves it back, wrapping at either end. autoFocus: true gives a component the focus when nothing else has it. An id lets you move the focus to it by name.
useFocusManager moves the focus from code: focus(id), focusNext, focusPrevious, enableFocus, disableFocus and activeId.
Every useInput hears every key. Its second argument, { isActive }, turns a handler off. A pane that should only answer while it has the focus passes { isActive: isFocused }.
Write the two panes#
Add useFocus and useFocusManager to the ink import:
;Then add the panes above Tasks. The list pane takes the arrow keys and space. The detail pane shows the selected task and takes x, which removes it:
;
;
Each pane runs in place with its own focus and its own handler. The border is cyan on the pane that has the focus and gray on the other. active is false while the text box from 640 is open, so typing a space or an x into it reaches neither pane. flexGrow={1} with flexBasis={0} on both panes splits the row between them in equal halves.
Hand the panes the state#
The tasks and the selection stay in Tasks. The panes get them as props, with functions that change them. Replace the component:
The page's own handler has no isActive, so it hears every key whichever pane has the focus. 1 and 2 call focus with a pane's id to jump straight to it.
Run it#
Start from a list of three:
The list pane has the focus from the start:
Tasks tasks.json 2 open
╭──────────────────────────────╮╭──────────────────────────────╮
│ > Write the README ││ Write the README │
│ Tag a release ││ done │
│ Answer the open issues ││ x removes it │
╰──────────────────────────────╯╰──────────────────────────────╯
Tab switches panes, a adds saved
Press Tab. The detail pane's border turns cyan. Press x and the README task is gone. Press Shift+Tab to go back to the list, then down and space:
Tasks tasks.json 1 open
╭──────────────────────────────╮╭──────────────────────────────╮
│ Tag a release ││ Answer the open issues │
│ > Answer the open issues ││ done │
│ ││ x removes it │
╰──────────────────────────────╯╰──────────────────────────────╯
Tab switches panes, a adds saved
Space does nothing while the detail pane has the focus and x does nothing while the list has it, since each handler is only active in its own pane.
Next up: 660. Run git and show its output.