diff --git a/pkg/cli/frame_model.go b/pkg/cli/frame_model.go index d0130688..e68730a6 100644 --- a/pkg/cli/frame_model.go +++ b/pkg/cli/frame_model.go @@ -29,3 +29,30 @@ type modelAdapter struct { func (a *modelAdapter) View(w, h int) string { return a.m.View(w, h) } func (a *modelAdapter) Init() tea.Cmd { return nil } func (a *modelAdapter) Update(tea.Msg) (FrameModel, tea.Cmd) { return a, nil } + +// KeyMap defines key bindings for Frame navigation. +// Use DefaultKeyMap() for sensible defaults, or build your own. +type KeyMap struct { + FocusNext tea.KeyType // Tab — cycle focus forward + FocusPrev tea.KeyType // Shift-Tab — cycle focus backward + FocusUp tea.KeyType // Up — spatial: move to Header + FocusDown tea.KeyType // Down — spatial: move to Footer + FocusLeft tea.KeyType // Left — spatial: move to Left sidebar + FocusRight tea.KeyType // Right — spatial: move to Right sidebar + Back tea.KeyType // Esc — Navigate back + Quit tea.KeyType // Ctrl-C — quit +} + +// DefaultKeyMap returns the standard Frame key bindings. +func DefaultKeyMap() KeyMap { + return KeyMap{ + FocusNext: tea.KeyTab, + FocusPrev: tea.KeyShiftTab, + FocusUp: tea.KeyUp, + FocusDown: tea.KeyDown, + FocusLeft: tea.KeyLeft, + FocusRight: tea.KeyRight, + Back: tea.KeyEsc, + Quit: tea.KeyCtrlC, + } +} diff --git a/pkg/cli/frame_test.go b/pkg/cli/frame_test.go index 87f3c16d..902cc12b 100644 --- a/pkg/cli/frame_test.go +++ b/pkg/cli/frame_test.go @@ -247,6 +247,20 @@ func (m *testFrameModel) Update(msg tea.Msg) (FrameModel, tea.Cmd) { return m, nil } +func TestKeyMap_Good(t *testing.T) { + t.Run("default keymap has expected bindings", func(t *testing.T) { + km := DefaultKeyMap() + assert.Equal(t, tea.KeyTab, km.FocusNext) + assert.Equal(t, tea.KeyShiftTab, km.FocusPrev) + assert.Equal(t, tea.KeyUp, km.FocusUp) + assert.Equal(t, tea.KeyDown, km.FocusDown) + assert.Equal(t, tea.KeyLeft, km.FocusLeft) + assert.Equal(t, tea.KeyRight, km.FocusRight) + assert.Equal(t, tea.KeyEsc, km.Back) + assert.Equal(t, tea.KeyCtrlC, km.Quit) + }) +} + // indexOf returns the position of substr in s, or -1 if not found. func indexOf(s, substr string) int { for i := range len(s) - len(substr) + 1 {