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'}
/>
)}