Skip to content

Commit 593fbfc

Browse files
committed
autoscroll and mouse wheel scroll
1 parent 2cdffef commit 593fbfc

File tree

1 file changed

+64
-17
lines changed

1 file changed

+64
-17
lines changed

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

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,14 @@
1-
import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react"
1+
import React, {
2+
forwardRef,
3+
memo,
4+
useCallback,
5+
useEffect,
6+
useImperativeHandle,
7+
useMemo,
8+
useRef,
9+
useState,
10+
WheelEvent,
11+
} from "react"
212
import { useAppTranslation } from "@/i18n/TranslationContext"
313
import {
414
CheckCheck,
@@ -105,6 +115,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
105115
const confirmDialogHandler = useRef<() => void>()
106116

107117
const [cachedState, setCachedState] = useState(extensionState)
118+
const scrollContainerRef = useRef<HTMLDivElement>(null) // Ref for the scrollable container
108119

109120
const {
110121
alwaysAllowReadOnly,
@@ -342,25 +353,56 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
342353
}
343354
}, [targetSection])
344355

345-
// Add effect to scroll the active tab into view when it changes
356+
// Add effect to conditionally scroll the active tab into view when it changes
346357
useEffect(() => {
347358
const activeTabElement = tabRefs.current[activeTab]?.current
348-
const tabContainer = document.querySelector(`.${settingsTabsContainer.split(" ")[0]}`)
359+
const containerElement = scrollContainerRef.current
349360

350-
if (activeTabElement && tabContainer) {
351-
// Calculate the scroll position to center the tab
352-
const containerWidth = tabContainer.clientWidth
353-
const tabWidth = activeTabElement.offsetWidth
354-
const tabLeft = activeTabElement.offsetLeft
355-
356-
// Center the tab in the container
357-
const scrollPosition = tabLeft - containerWidth / 2 + tabWidth / 2
361+
if (activeTabElement && containerElement) {
362+
// Calculate the visible range within the scroll container
363+
const visibleLeft = containerElement.scrollLeft
364+
const visibleRight = containerElement.scrollLeft + containerElement.clientWidth
358365

359-
// Set the scroll position directly for a snappier experience
360-
tabContainer.scrollLeft = scrollPosition
366+
// Calculate the tab's position within the scroll container
367+
const tabLeft = activeTabElement.offsetLeft
368+
const tabRight = activeTabElement.offsetLeft + activeTabElement.offsetWidth
369+
370+
// Check if the tab is fully within the visible range
371+
const isVisible = tabLeft >= visibleLeft && tabRight <= visibleRight
372+
373+
// Only scroll if the tab is not fully visible
374+
if (!isVisible) {
375+
activeTabElement.scrollIntoView({
376+
behavior: "auto", // Use instant scrolling
377+
block: "nearest",
378+
inline: "center",
379+
})
380+
}
361381
}
362382
}, [activeTab])
363383

384+
// Handle horizontal scrolling with mouse wheel
385+
const handleWheelScroll = useCallback((event: WheelEvent<HTMLDivElement>) => {
386+
const container = scrollContainerRef.current
387+
if (container) {
388+
// Use deltaY for vertical scroll wheels (most common)
389+
// Adjust sensitivity as needed
390+
const scrollAmount = event.deltaY * 2 // Multiplier for sensitivity
391+
392+
// Check if scrolling is possible
393+
if (container.scrollWidth > container.clientWidth) {
394+
container.scrollLeft += scrollAmount
395+
// Prevent default page scrolling if horizontal scroll happened
396+
if (
397+
(scrollAmount < 0 && container.scrollLeft > 0) ||
398+
(scrollAmount > 0 && container.scrollLeft < container.scrollWidth - container.clientWidth)
399+
) {
400+
event.preventDefault()
401+
}
402+
}
403+
}
404+
}, [])
405+
364406
return (
365407
<Tab>
366408
<TabHeader className="flex justify-between items-center gap-2">
@@ -393,9 +435,15 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
393435
</TabHeader>
394436

395437
{/* Tab list with overflow dropdown */}
396-
<div className="flex items-center">
397-
{/* Show only the first 5 tabs and the active tab if it's not in the first 5 */}
398-
<div className={cn(settingsTabsContainer, scrollbarHideClasses, "w-full")}>
438+
<div className="flex items-center pr-5">
439+
{" "}
440+
{/* Added pr-5 here */}
441+
{/* Scrollable tab container */}
442+
<div
443+
ref={scrollContainerRef} // Assign ref
444+
className={cn(settingsTabsContainer, scrollbarHideClasses, "w-full", "px-5")}
445+
onWheel={handleWheelScroll} // Add wheel handler
446+
>
399447
<TabList
400448
value={activeTab}
401449
onValueChange={(value) => handleTabChange(value as SectionName)}
@@ -422,7 +470,6 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
422470
))}
423471
</TabList>
424472
</div>
425-
426473
{/* "More" dropdown button - always show it */}
427474
<DropdownMenu>
428475
<DropdownMenuTrigger asChild>

0 commit comments

Comments
 (0)