Action menu¶
pkg/action turns a screen's verbs into data (an action.Set) and renders
them in action.Menu: a bordered picker that sizes itself to its content,
anchors where the user right-clicked or centers itself for the keyboard, shows
unavailable verbs dimmed with a reason, and resolves to a ChosenMsg.
Under the app shell you don't host the menu at all: set app.Options.ActionsKey
and implement action.Provider. That's covered in
Verbs and multi-select, including every Action and
Set field. This page is the component itself, for hosting it without the
shell.
Hosting¶
func (s *Screen) openMenu(at *mouse.Msg) {
opts := s.t.Actions()
opts.Set = s.Actions()
s.menu = action.New(opts)
if at != nil {
s.menu.Anchor(at.X, at.Y)
} else {
s.menu.Center()
}
s.menuUp = true
}
func (s *Screen) Update(msg tea.Msg) (screen.Screen, tea.Cmd) {
if s.menuUp {
switch m := msg.(type) {
case action.ChosenMsg:
s.menuUp = false
return s, s.run(m.Action, m.Targets)
case action.CancelledMsg:
s.menuUp = false
return s, nil
}
var cmd tea.Cmd
s.menu, cmd = s.menu.Update(msg)
return s, cmd
}
// …
}
func (s *Screen) Layout() layout.Node {
base := layout.Sized(&s.table)
if s.menuUp {
return layout.ZStack(base, layout.Sized(&s.menu)) // no Center: it places itself
}
return base
}
The menu reports what was chosen and never runs anything; the host decides
(run Run in the background, return Do()'s command, confirm first if
Confirm is set).
Options¶
| Field | Type | Default | Meaning |
|---|---|---|---|
Title |
string |
"Actions" |
Border title; the set's Target is appended. |
Set |
action.Set |
The verbs and what they act on. | |
LabelStyle, DescStyle, KeyStyle |
lipgloss.Style |
theme | Row text. |
SelectedStyle |
lipgloss.Style |
bold accent | Cursor row. |
DisabledStyle |
lipgloss.Style |
subtle | Unavailable rows. |
MultiReason |
string |
"one item at a time" |
Reason shown on a non-Multi verb under a multi-selection. |
RunningReason |
string |
"already running" |
Reason shown on an Exclusive verb already in flight. |
Keys |
action.Keys |
DefaultKeys() |
Key bindings. |
ActiveColor, InactiveColor, ActiveBorder, InactiveBorder, Glyphs, SlotBrackets |
theme (overlay border) | Pane chrome. |
Keys¶
| Key | Binding field | Action |
|---|---|---|
↑/k, ↓/j |
Up, Down |
move (skipping disabled rows) |
g, G, ctrl+u, ctrl+d |
Top, Bottom, HalfUp, HalfDown |
jump (when the menu scrolls) |
enter |
Choose |
choose |
esc |
Cancel |
dismiss |
an action's Key |
choose that action directly |
Mouse: click a row to choose it, click outside to dismiss. A right-press
outside the menu emits action.RetargetMsg{Event} so the host can move its
selection to what's under the pointer and reopen.
Methods¶
| Method | Does |
|---|---|
Anchor(x, y) |
Place the top-left at a point (clamped on screen). |
Center() |
Center within the bounds. |
SetActions(set), Set() |
Swap or read the verbs. |
SetRunning(map[string]bool) |
Which Exclusive actions are in flight, keyed by action.RunKey(a, target). |
Selected(), Cursor(), SetCursor(i) |
Cursor. |
CanScroll(), Rect() |
Layout state. |
Messages¶
| Message | When |
|---|---|
action.ChosenMsg{Action, Target, Targets} |
a verb was picked |
action.CancelledMsg{} |
dismissed |
action.RetargetMsg{Event} |
right-press outside the open menu |
action.Validate(set) []error catches authoring mistakes; call it from a test.
See examples/patterns/actions and examples/patterns/multiselect.