Skip to content

Commit ad07bf4

Browse files
committed
fix: preserve scroll position when switching tabs in settings
1 parent ae8a639 commit ad07bf4

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

webview-ui/src/components/common/Tab.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export const TabHeader = ({ className, children, ...props }: TabProps) => (
1717
</div>
1818
)
1919

20-
export const TabContent = ({ className, children, ...props }: TabProps) => {
20+
export const TabContent = forwardRef<HTMLDivElement, TabProps>(({ className, children, ...props }, ref) => {
2121
const { renderContext } = useExtensionState()
2222

2323
const onWheel = useCallback(
@@ -40,11 +40,11 @@ export const TabContent = ({ className, children, ...props }: TabProps) => {
4040
)
4141

4242
return (
43-
<div className={cn("flex-1 overflow-auto p-5", className)} onWheel={onWheel} {...props}>
43+
<div ref={ref} className={cn("flex-1 overflow-auto p-5", className)} onWheel={onWheel} {...props}>
4444
{children}
4545
</div>
4646
)
47-
}
47+
})
4848

4949
export const TabList = forwardRef<
5050
HTMLDivElement,

webview-ui/src/components/settings/SettingsView.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
112112
: "providers",
113113
)
114114

115+
const scrollPositions = useRef<Record<SectionName, number>>(
116+
Object.fromEntries(sectionNames.map((s) => [s, 0])) as Record<SectionName, number>,
117+
)
118+
const contentRef = useRef<HTMLDivElement | null>(null)
119+
115120
const prevApiConfigName = useRef(currentApiConfigName)
116121
const confirmDialogHandler = useRef<() => void>()
117122

@@ -398,12 +403,22 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
398403
// Handle tab changes with unsaved changes check
399404
const handleTabChange = useCallback(
400405
(newTab: SectionName) => {
401-
// Directly switch tab without checking for unsaved changes
406+
if (contentRef.current) {
407+
scrollPositions.current[activeTab] = contentRef.current.scrollTop
408+
}
402409
setActiveTab(newTab)
403410
},
404-
[], // No dependency on isChangeDetected needed anymore
411+
[activeTab],
405412
)
406413

414+
useEffect(() => {
415+
requestAnimationFrame(() => {
416+
if (contentRef.current) {
417+
contentRef.current.scrollTop = scrollPositions.current[activeTab] ?? 0
418+
}
419+
})
420+
}, [activeTab])
421+
407422
// Store direct DOM element refs for each tab
408423
const tabRefs = useRef<Record<SectionName, HTMLButtonElement | null>>(
409424
Object.fromEntries(sectionNames.map((name) => [name, null])) as Record<SectionName, HTMLButtonElement | null>,
@@ -579,7 +594,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
579594
</TabList>
580595

581596
{/* Content area */}
582-
<TabContent className="p-0 flex-1 overflow-auto">
597+
<TabContent ref={contentRef} className="p-0 flex-1 overflow-auto">
583598
{/* Providers Section */}
584599
{activeTab === "providers" && (
585600
<div>

0 commit comments

Comments
 (0)