From ad07bf4e0dacf1c7e937e3fcb5a7c8a36335996a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B7=A1=E8=8D=89?= <47478484+DC-Dancao@users.noreply.github.com> Date: Tue, 2 Sep 2025 08:00:39 +0800 Subject: [PATCH 1/2] fix: preserve scroll position when switching tabs in settings --- webview-ui/src/components/common/Tab.tsx | 6 +++--- .../src/components/settings/SettingsView.tsx | 21 ++++++++++++++++--- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/webview-ui/src/components/common/Tab.tsx b/webview-ui/src/components/common/Tab.tsx index 99c2b7b4b0..06e392a4da 100644 --- a/webview-ui/src/components/common/Tab.tsx +++ b/webview-ui/src/components/common/Tab.tsx @@ -17,7 +17,7 @@ export const TabHeader = ({ className, children, ...props }: TabProps) => ( ) -export const TabContent = ({ className, children, ...props }: TabProps) => { +export const TabContent = forwardRef(({ className, children, ...props }, ref) => { const { renderContext } = useExtensionState() const onWheel = useCallback( @@ -40,11 +40,11 @@ export const TabContent = ({ className, children, ...props }: TabProps) => { ) return ( -
+
{children}
) -} +}) export const TabList = forwardRef< HTMLDivElement, diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index f680f3e5fe..1827cc38d5 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -112,6 +112,11 @@ const SettingsView = forwardRef(({ onDone, t : "providers", ) + const scrollPositions = useRef>( + Object.fromEntries(sectionNames.map((s) => [s, 0])) as Record, + ) + const contentRef = useRef(null) + const prevApiConfigName = useRef(currentApiConfigName) const confirmDialogHandler = useRef<() => void>() @@ -398,12 +403,22 @@ const SettingsView = forwardRef(({ onDone, t // Handle tab changes with unsaved changes check const handleTabChange = useCallback( (newTab: SectionName) => { - // Directly switch tab without checking for unsaved changes + if (contentRef.current) { + scrollPositions.current[activeTab] = contentRef.current.scrollTop + } setActiveTab(newTab) }, - [], // No dependency on isChangeDetected needed anymore + [activeTab], ) + useEffect(() => { + requestAnimationFrame(() => { + if (contentRef.current) { + contentRef.current.scrollTop = scrollPositions.current[activeTab] ?? 0 + } + }) + }, [activeTab]) + // Store direct DOM element refs for each tab const tabRefs = useRef>( Object.fromEntries(sectionNames.map((name) => [name, null])) as Record, @@ -579,7 +594,7 @@ const SettingsView = forwardRef(({ onDone, t {/* Content area */} - + {/* Providers Section */} {activeTab === "providers" && (
From 36489418a7af5bd0a5281346fe204a89ed9e1ab5 Mon Sep 17 00:00:00 2001 From: Daniel Riccio Date: Wed, 3 Sep 2025 18:17:02 -0500 Subject: [PATCH 2/2] ui(settings): restore scroll synchronously to prevent flicker; dx(ui): name TabContent for clearer DevTools --- webview-ui/src/components/common/Tab.tsx | 1 + webview-ui/src/components/settings/SettingsView.tsx | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/webview-ui/src/components/common/Tab.tsx b/webview-ui/src/components/common/Tab.tsx index 06e392a4da..495bb1b34b 100644 --- a/webview-ui/src/components/common/Tab.tsx +++ b/webview-ui/src/components/common/Tab.tsx @@ -45,6 +45,7 @@ export const TabContent = forwardRef(({ className, chi
) }) +TabContent.displayName = "TabContent" export const TabList = forwardRef< HTMLDivElement, diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 1827cc38d5..632873308e 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -411,12 +411,10 @@ const SettingsView = forwardRef(({ onDone, t [activeTab], ) - useEffect(() => { - requestAnimationFrame(() => { - if (contentRef.current) { - contentRef.current.scrollTop = scrollPositions.current[activeTab] ?? 0 - } - }) + useLayoutEffect(() => { + if (contentRef.current) { + contentRef.current.scrollTop = scrollPositions.current[activeTab] ?? 0 + } }, [activeTab]) // Store direct DOM element refs for each tab