panel-to-panel focus traversal via F6 / Shift+F6 (T-105)
Each SlotHost now owns a FocusScopeNode and registers it with FocusTracker on mount. The render is wrapped in FocusScope + FocusTraversalGroup so Tab stays within a panel and slot-level focus is observable. When a slot's scope gains focus, SlotHost pushes (slot, activeContributionId) to FocusTracker — this collapses the parallel-tracker model the consultant flagged. FocusTracker keeps its setActive surface for explicit callers (palette, etc.) but slot-scoped tab activation feeds it automatically. Two new intents, two new bindings: FocusNextPanelIntent → F6 FocusPreviousPanelIntent → Shift+F6 (VS Code convention; preset YAML.) The cycle skips slots without a registered scope, so a layout that hides the context panel doesn't strand focus on a missing target. Fewer than two registered → no-op. SlotHost split into a stateful outer (scope + registry) and a stateless `_SlotBody` (the existing slot-specific rendering), keeping the build straightforward. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,19 @@ library;
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
// -- Panel-to-panel focus traversal -----------------------------------------
|
||||
|
||||
/// Move focus to the next panel in `FocusTracker.traversalOrder`
|
||||
/// (sidebar → workspace → context). Bound to F6 by default.
|
||||
class FocusNextPanelIntent extends Intent {
|
||||
const FocusNextPanelIntent();
|
||||
}
|
||||
|
||||
/// Move focus to the previous panel. Bound to Shift+F6 by default.
|
||||
class FocusPreviousPanelIntent extends Intent {
|
||||
const FocusPreviousPanelIntent();
|
||||
}
|
||||
|
||||
// -- Command palette --------------------------------------------------------
|
||||
|
||||
/// Open the command palette.
|
||||
@@ -76,6 +89,8 @@ class InvokeCommandIntent extends Intent {
|
||||
final Map<String, Intent Function()> builtinIntents = {
|
||||
'activate': () => const ActivateIntent(),
|
||||
'dismiss': () => const DismissIntent(),
|
||||
'focus.nextPanel': () => const FocusNextPanelIntent(),
|
||||
'focus.previousPanel': () => const FocusPreviousPanelIntent(),
|
||||
'palette.open': () => const PaletteOpenIntent(),
|
||||
'palette.selectNext': () => const PaletteSelectNextIntent(),
|
||||
'palette.selectPrevious': () => const PaletteSelectPreviousIntent(),
|
||||
|
||||
Reference in New Issue
Block a user