fix: deactivate old pane border when keyboard overrides hover focus
- commit
- aff19992d14793b9004ee2128db2cc4034b88014
- author
- brice · · 2026-01-01 10:39 UTC
- parent
- f2d203b
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +20 -0
M internal/ui/component/workspace_view.go +12 -0
| @@ -357,6 +357,18 @@ func (wv *WorkspaceView) FocusPane(paneID entity.PaneID) bool { | |||
| 357 | 357 | return pv.GrabFocus() | |
| 358 | 358 | } | |
| 359 | 359 | ||
| 360 | + | // DeactivatePane removes the active visual indicator from a pane. | |
| 361 | + | // This is used when keyboard navigation overrides mouse hover focus. | |
| 362 | + | func (wv *WorkspaceView) DeactivatePane(paneID entity.PaneID) { | |
| 363 | + | wv.mu.RLock() | |
| 364 | + | pv, ok := wv.paneViews[paneID] | |
| 365 | + | wv.mu.RUnlock() | |
| 366 | + | ||
| 367 | + | if ok && pv != nil { | |
| 368 | + | pv.SetActive(false) | |
| 369 | + | } | |
| 370 | + | } | |
| 371 | + | ||
| 360 | 372 | // SetWebViewWidget attaches a WebView widget to a specific pane. | |
| 361 | 373 | func (wv *WorkspaceView) SetWebViewWidget(paneID entity.PaneID, widget layout.Widget) error { | |
| 362 | 374 | wv.mu.RLock() | |
| @@ -357,6 +357,18 @@ func (wv *WorkspaceView) FocusPane(paneID entity.PaneID) bool { | |||||
| 357 | return pv.GrabFocus() | 357 | return pv.GrabFocus() | ||
| 358 | } | 358 | } | ||
| 359 | 359 | ||||
| 360 | + | // DeactivatePane removes the active visual indicator from a pane. | |||
| 361 | + | // This is used when keyboard navigation overrides mouse hover focus. | |||
| 362 | + | func (wv *WorkspaceView) DeactivatePane(paneID entity.PaneID) { | |||
| 363 | + | wv.mu.RLock() | |||
| 364 | + | pv, ok := wv.paneViews[paneID] | |||
| 365 | + | wv.mu.RUnlock() | |||
| 366 | + | ||||
| 367 | + | if ok && pv != nil { | |||
| 368 | + | pv.SetActive(false) | |||
| 369 | + | } | |||
| 370 | + | } | |||
| 371 | + | ||||
| 360 | // SetWebViewWidget attaches a WebView widget to a specific pane. | 372 | // SetWebViewWidget attaches a WebView widget to a specific pane. | ||
| 361 | func (wv *WorkspaceView) SetWebViewWidget(paneID entity.PaneID, widget layout.Widget) error { | 373 | func (wv *WorkspaceView) SetWebViewWidget(paneID entity.PaneID, widget layout.Widget) error { | ||
| 362 | wv.mu.RLock() | 374 | wv.mu.RLock() | ||
M internal/ui/coordinator/workspace.go +8 -0
| @@ -1141,6 +1141,9 @@ func (c *WorkspaceCoordinator) FocusPane(ctx context.Context, direction usecase. | |||
| 1141 | 1141 | return nil | |
| 1142 | 1142 | } | |
| 1143 | 1143 | ||
| 1144 | + | // Save old active pane ID before navigation updates the domain model | |
| 1145 | + | oldActivePaneID := ws.ActivePaneID | |
| 1146 | + | ||
| 1144 | 1147 | // Use geometric navigation if focus manager is available | |
| 1145 | 1148 | var newPane *entity.PaneNode | |
| 1146 | 1149 | var err error | |
| @@ -1169,6 +1172,11 @@ func (c *WorkspaceCoordinator) FocusPane(ctx context.Context, direction usecase. | |||
| 1169 | 1172 | wsView.CancelAllPendingHovers() | |
| 1170 | 1173 | wsView.SuppressHover(component.KeyboardFocusSuppressDuration) | |
| 1171 | 1174 | ||
| 1175 | + | // Deactivate old pane explicitly (domain model already updated by NavigateGeometric) | |
| 1176 | + | if oldActivePaneID != "" && oldActivePaneID != newPane.Pane.ID { | |
| 1177 | + | wsView.DeactivatePane(oldActivePaneID) | |
| 1178 | + | } | |
| 1179 | + | ||
| 1172 | 1180 | // Update the workspace view's active pane | |
| 1173 | 1181 | if err := wsView.SetActivePaneID(newPane.Pane.ID); err != nil { | |
| 1174 | 1182 | log.Warn().Err(err).Msg("failed to update active pane in view") | |
| @@ -1141,6 +1141,9 @@ func (c *WorkspaceCoordinator) FocusPane(ctx context.Context, direction usecase. | |||||
| 1141 | return nil | 1141 | return nil | ||
| 1142 | } | 1142 | } | ||
| 1143 | 1143 | ||||
| 1144 | + | // Save old active pane ID before navigation updates the domain model | |||
| 1145 | + | oldActivePaneID := ws.ActivePaneID | |||
| 1146 | + | ||||
| 1144 | // Use geometric navigation if focus manager is available | 1147 | // Use geometric navigation if focus manager is available | ||
| 1145 | var newPane *entity.PaneNode | 1148 | var newPane *entity.PaneNode | ||
| 1146 | var err error | 1149 | var err error | ||
| @@ -1169,6 +1172,11 @@ func (c *WorkspaceCoordinator) FocusPane(ctx context.Context, direction usecase. | |||||
| 1169 | wsView.CancelAllPendingHovers() | 1172 | wsView.CancelAllPendingHovers() | ||
| 1170 | wsView.SuppressHover(component.KeyboardFocusSuppressDuration) | 1173 | wsView.SuppressHover(component.KeyboardFocusSuppressDuration) | ||
| 1171 | 1174 | ||||
| 1175 | + | // Deactivate old pane explicitly (domain model already updated by NavigateGeometric) | |||
| 1176 | + | if oldActivePaneID != "" && oldActivePaneID != newPane.Pane.ID { | |||
| 1177 | + | wsView.DeactivatePane(oldActivePaneID) | |||
| 1178 | + | } | |||
| 1179 | + | ||||
| 1172 | // Update the workspace view's active pane | 1180 | // Update the workspace view's active pane | ||
| 1173 | if err := wsView.SetActivePaneID(newPane.Pane.ID); err != nil { | 1181 | if err := wsView.SetActivePaneID(newPane.Pane.ID); err != nil { | ||
| 1174 | log.Warn().Err(err).Msg("failed to update active pane in view") | 1182 | log.Warn().Err(err).Msg("failed to update active pane in view") | ||