From 9a33478e4ab2cce5eaff137e29294fc58ec5ce2b Mon Sep 17 00:00:00 2001 From: Roo Code Date: Thu, 11 Sep 2025 04:21:29 +0000 Subject: [PATCH 1/2] fix: center active mode in selector dropdown on open - Added refs to track selected item and scroll container - Implemented scroll-to-center logic when popover opens - Selected mode now appears centered in viewport instead of list starting at top - Fixes issue where users had to manually scroll to find active mode Fixes #7882 --- .../src/components/chat/ModeSelector.tsx | 80 +++++++++++++------ 1 file changed, 55 insertions(+), 25 deletions(-) diff --git a/webview-ui/src/components/chat/ModeSelector.tsx b/webview-ui/src/components/chat/ModeSelector.tsx index 2ae9279fa8e..8a37c9082d1 100644 --- a/webview-ui/src/components/chat/ModeSelector.tsx +++ b/webview-ui/src/components/chat/ModeSelector.tsx @@ -44,6 +44,8 @@ export const ModeSelector = ({ const [open, setOpen] = React.useState(false) const [searchValue, setSearchValue] = React.useState("") const searchInputRef = React.useRef(null) + const selectedItemRef = React.useRef(null) + const scrollContainerRef = React.useRef(null) const portalContainer = useRooPortal("roo-portal") const { hasOpenedModeSelector, setHasOpenedModeSelector } = useExtensionState() const { t } = useAppTranslation() @@ -149,10 +151,34 @@ export const ModeSelector = ({ [trackModeSelectorOpened], ) - // Auto-focus search input when popover opens. + // Auto-focus search input and scroll to selected item when popover opens. React.useEffect(() => { - if (open && searchInputRef.current) { - searchInputRef.current.focus() + if (open) { + // Focus search input + if (searchInputRef.current) { + searchInputRef.current.focus() + } + + // Scroll to selected item with a small delay to ensure DOM is ready + setTimeout(() => { + if (selectedItemRef.current && scrollContainerRef.current) { + const container = scrollContainerRef.current + const item = selectedItemRef.current + + // Calculate positions + const containerHeight = container.clientHeight + const itemTop = item.offsetTop + const itemHeight = item.offsetHeight + + // Center the item in the container + const scrollPosition = itemTop - containerHeight / 2 + itemHeight / 2 + + container.scrollTo({ + top: Math.max(0, scrollPosition), + behavior: "instant", + }) + } + }, 0) } }, [open]) @@ -223,36 +249,40 @@ export const ModeSelector = ({ )} {/* Mode List */} -
+
{filteredModes.length === 0 && searchValue ? (
{t("chat:modeSelector.noResults")}
) : (
- {filteredModes.map((mode) => ( -
handleSelect(mode.slug)} - className={cn( - "px-3 py-1.5 text-sm cursor-pointer flex items-center", - "hover:bg-vscode-list-hoverBackground", - mode.slug === value - ? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground" - : "", - )} - data-testid="mode-selector-item"> -
-
{mode.name}
- {mode.description && ( -
- {mode.description} -
+ {filteredModes.map((mode) => { + const isSelected = mode.slug === value + return ( +
handleSelect(mode.slug)} + className={cn( + "px-3 py-1.5 text-sm cursor-pointer flex items-center", + "hover:bg-vscode-list-hoverBackground", + isSelected + ? "bg-vscode-list-activeSelectionBackground text-vscode-list-activeSelectionForeground" + : "", )} + data-testid="mode-selector-item"> +
+
{mode.name}
+ {mode.description && ( +
+ {mode.description} +
+ )} +
+ {isSelected && }
- {mode.slug === value && } -
- ))} + ) + })}
)}
From 268e6c51e4cabd5365ce8e0999373143f26f21b5 Mon Sep 17 00:00:00 2001 From: daniel-lxs Date: Thu, 11 Sep 2025 13:06:01 -0500 Subject: [PATCH 2/2] fix: improve scroll-to-center reliability with requestAnimationFrame - Replace setTimeout with requestAnimationFrame for more reliable DOM synchronization - Add proper boundary checking to prevent scrolling past container limits - Ensure scroll position stays within valid bounds using Math.min/max --- webview-ui/src/components/chat/ModeSelector.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/webview-ui/src/components/chat/ModeSelector.tsx b/webview-ui/src/components/chat/ModeSelector.tsx index 8a37c9082d1..331660143b7 100644 --- a/webview-ui/src/components/chat/ModeSelector.tsx +++ b/webview-ui/src/components/chat/ModeSelector.tsx @@ -159,8 +159,7 @@ export const ModeSelector = ({ searchInputRef.current.focus() } - // Scroll to selected item with a small delay to ensure DOM is ready - setTimeout(() => { + requestAnimationFrame(() => { if (selectedItemRef.current && scrollContainerRef.current) { const container = scrollContainerRef.current const item = selectedItemRef.current @@ -173,12 +172,16 @@ export const ModeSelector = ({ // Center the item in the container const scrollPosition = itemTop - containerHeight / 2 + itemHeight / 2 + // Ensure we don't scroll past boundaries + const maxScroll = container.scrollHeight - containerHeight + const finalScrollPosition = Math.min(Math.max(0, scrollPosition), maxScroll) + container.scrollTo({ - top: Math.max(0, scrollPosition), + top: finalScrollPosition, behavior: "instant", }) } - }, 0) + }) } }, [open])