diff --git a/packages/cli/src/ui/components/shared/BaseSettingsDialog.tsx b/packages/cli/src/ui/components/shared/BaseSettingsDialog.tsx index 05cef4fcf2e..134ef39b30a 100644 --- a/packages/cli/src/ui/components/shared/BaseSettingsDialog.tsx +++ b/packages/cli/src/ui/components/shared/BaseSettingsDialog.tsx @@ -188,12 +188,11 @@ export function BaseSettingsDialog({ return () => clearInterval(interval); }, [editingKey]); - // Ensure focus stays on settings when scope selection is hidden - useEffect(() => { - if (!showScopeSelector && focusSection === 'scope') { - setFocusSection('settings'); - } - }, [showScopeSelector, focusSection]); + // When the scope selector is hidden, treat any 'scope' focus as 'settings'. + // Derived on render rather than via an effect — effects are for subscribing + // to external systems, not computing values from existing state/props. + const effectiveFocusSection = + !showScopeSelector && focusSection === 'scope' ? 'settings' : focusSection; // Scope selector items const scopeItems = getScopeItems().map((item) => ({ @@ -229,16 +228,8 @@ export function BaseSettingsDialog({ setEditCursorPos(0); }, [editingKey, editBuffer, currentItem, onEditCommit]); - // Handle scope highlight (for RadioButtonSelect) - const handleScopeHighlight = useCallback( - (scope: LoadableSettingScope) => { - onScopeChange?.(scope); - }, - [onScopeChange], - ); - - // Handle scope select (for RadioButtonSelect) - const handleScopeSelect = useCallback( + // Single callback used for both onSelect and onHighlight on RadioButtonSelect + const handleScopeChange = useCallback( (scope: LoadableSettingScope) => { onScopeChange?.(scope); }, @@ -360,7 +351,7 @@ export function BaseSettingsDialog({ } // Not in edit mode - handle navigation and actions - if (focusSection === 'settings') { + if (effectiveFocusSection === 'settings') { // Up/Down navigation with wrap-around if (keyMatchers[Command.DIALOG_NAVIGATION_UP](key)) { const newIndex = activeIndex > 0 ? activeIndex - 1 : items.length - 1; @@ -427,7 +418,7 @@ export function BaseSettingsDialog({ }, { isActive: true, - priority: focusSection === 'settings' && !editingKey, + priority: effectiveFocusSection === 'settings' && !editingKey, }, ); @@ -444,10 +435,10 @@ export function BaseSettingsDialog({ {/* Title */} - {focusSection === 'settings' ? '> ' : ' '} + {effectiveFocusSection === 'settings' ? '> ' : ' '} {title}{' '} @@ -459,7 +450,7 @@ export function BaseSettingsDialog({ borderColor={ editingKey ? theme.border.default - : focusSection === 'settings' + : effectiveFocusSection === 'settings' ? theme.ui.focus : theme.border.default } @@ -468,7 +459,7 @@ export function BaseSettingsDialog({ marginTop={1} > @@ -492,7 +483,8 @@ export function BaseSettingsDialog({ {visibleItems.map((item, idx) => { const globalIndex = idx + scrollOffset; const isActive = - focusSection === 'settings' && activeIndex === globalIndex; + effectiveFocusSection === 'settings' && + activeIndex === globalIndex; // Compute display value with edit mode cursor let displayValue: string; @@ -604,19 +596,19 @@ export function BaseSettingsDialog({ {/* Scope Selection */} {showScopeSelector && ( - - {focusSection === 'scope' ? '> ' : ' '}Apply To + + {effectiveFocusSection === 'scope' ? '> ' : ' '}Apply To item.value === selectedScope, )} - onSelect={handleScopeSelect} - onHighlight={handleScopeHighlight} - isFocused={focusSection === 'scope'} - showNumbers={focusSection === 'scope'} - priority={focusSection === 'scope'} + onSelect={handleScopeChange} + onHighlight={handleScopeChange} + isFocused={effectiveFocusSection === 'scope'} + showNumbers={effectiveFocusSection === 'scope'} + priority={effectiveFocusSection === 'scope'} /> )}