11import { GlassView } from "expo-glass-effect" ;
2- import { useState } from "react" ;
2+ import { useEffect , useRef , useState , type ComponentRef } from "react" ;
33import { Pressable , ScrollView , View } from "react-native" ;
44import Animated , { useAnimatedStyle , useReducedMotion , withTiming } from "react-native-reanimated" ;
55import { withUniwind } from "uniwind" ;
@@ -25,8 +25,13 @@ export interface TabsProps<Value extends string> {
2525export function Tabs < Value extends string > ( props : TabsProps < Value > ) {
2626 const { themeAppearance } = useAppearancePreferences ( ) ;
2727 const reduceMotion = useReducedMotion ( ) ;
28+ const scrollView = useRef < ComponentRef < typeof ScrollView > > ( null ) ;
2829 const [ frames , setFrames ] = useState < Partial < Record < Value , { x : number ; width : number } > > > ( { } ) ;
2930 const frame = frames [ props . selected ] ;
31+ // oxlint-disable-next-line t3code/no-unreasoned-state-sync -- keeps the selected tab visible in the native scroll viewport
32+ useEffect ( ( ) => {
33+ if ( frame ) scrollView . current ?. scrollTo ( { x : frame . x , animated : false } ) ;
34+ } , [ frame ] ) ;
3035 const duration = reduceMotion ? 0 : 220 ;
3136 const indicatorStyle = useAnimatedStyle ( ( ) => ( {
3237 width : withTiming ( frame ?. width ?? 0 , { duration } ) ,
@@ -35,6 +40,7 @@ export function Tabs<Value extends string>(props: TabsProps<Value>) {
3540
3641 return (
3742 < ScrollView
43+ ref = { scrollView }
3844 horizontal
3945 showsHorizontalScrollIndicator = { false }
4046 className = { cn ( "grow-0" , props . className ) }
0 commit comments