import { memo, useCallback, useEffect, useRef } from 'react'; import { Pressable, ScrollView, StyleSheet, Text, View, useWindowDimensions } from 'react-native'; type Category = { id: string; label: string; }; type CategoryTabsProps = { categories: Category[]; activeId: string; onChange: (id: string) => void; }; export function CategoryTabs({ categories, activeId, onChange }: CategoryTabsProps) { const scrollViewRef = useRef(null); const tabPositionsRef = useRef>(new Map()); const containerWidthRef = useRef(0); const { width: screenWidth } = useWindowDimensions(); const scrollToActiveTab = useCallback(() => { if (!activeId) { console.log('[CategoryTabs] No activeId'); return; } const position = tabPositionsRef.current.get(activeId); if (!position || !scrollViewRef.current) { console.log('[CategoryTabs] Missing position or ref:', { position, hasRef: !!scrollViewRef.current }); return; } const centerOffset = screenWidth / 2; const tabCenter = position.x + position.width / 2; const scrollX = tabCenter - centerOffset; const maxScrollX = Math.max(0, containerWidthRef.current - screenWidth); const targetX = Math.max(0, Math.min(scrollX, maxScrollX)); console.log('[CategoryTabs] Scrolling to:', { activeId, position, screenWidth, tabCenter, targetX, containerWidth: containerWidthRef.current, }); scrollViewRef.current.scrollTo({ x: targetX, animated: true, }); }, [activeId, screenWidth]); useEffect(() => { const timer = setTimeout(scrollToActiveTab, 150); return () => clearTimeout(timer); }, [scrollToActiveTab]); const handleContentSizeChange = useCallback((width: number) => { containerWidthRef.current = width; console.log('[CategoryTabs] Content size:', width); }, []); return ( {categories.map((category, index) => ( { tabPositionsRef.current.set(category.id, { x: layout.x, width: layout.width, }); console.log(`[CategoryTabs] Tab layout [${category.label}]:`, layout); }} /> ))} ); } type CategoryTabItemProps = { category: Category; isActive: boolean; onPress: (id: string) => void; onLayout: (layout: { x: number; width: number }) => void; }; const CategoryTabItem = memo(({ category, isActive, onPress, onLayout }: CategoryTabItemProps) => { return ( onPress(category.id)} style={styles.tabButton} onLayout={(event) => { const { x, width } = event.nativeEvent.layout; onLayout({ x, width }); }} > {category.label} ); }); CategoryTabItem.displayName = 'CategoryTabItem'; const styles = StyleSheet.create({ scrollView: { flexGrow: 0, flexShrink: 0, }, container: { paddingVertical: 10, paddingHorizontal: 6, }, tabButton: { alignItems: 'center', marginRight: 20, paddingBottom: 10, }, label: { color: '#7F8794', fontSize: 15, fontWeight: '600', letterSpacing: 0.3, }, labelActive: { color: '#C7FF00', }, indicator: { alignSelf: 'stretch', height: 3, marginTop: 8, backgroundColor: 'transparent', borderRadius: 999, }, indicatorActive: { backgroundColor: '#C7FF00', }, });