import React, { useEffect, useMemo, useRef } from 'react'; import PagerView from 'react-native-pager-view'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import type { TabsProps } from '.'; import SceneView from './SceneView'; import type { ScrollableTabHeaderProps } from './ScrollableTabsHeader/ScrollableTabsHeader'; import ScrollableTabHeader from './ScrollableTabsHeader/ScrollableTabsHeader'; import { TabContainer } from './StyledScrollableTabs'; import useHandlePageScroll from './useHandlePageScroll'; import { ScreenContext, TabContext } from './useIsFocused'; export interface ScrollableTabProps extends Omit { variant?: 'underlined' | 'highlighted'; header?: (props: ScrollableTabHeaderProps) => React.ReactElement | null; } const ScrollableTab = ({ onTabPress, selectedTabKey, tabs, containerStyle, barStyle, lazy = false, lazyPreloadDistance = 1, swipeEnabled = true, testID: componentTestID, variant = 'highlighted', header, }: ScrollableTabProps) => { const pagerViewRef = useRef(null); const insets = useSafeAreaInsets(); const selectedTabIndex = tabs.findIndex( (item) => item.key === selectedTabKey ); const { hasScrolled, onPageScrollStateChanged } = useHandlePageScroll(); useEffect(() => { let timeoutHandle: ReturnType; if (selectedTabIndex !== -1) { // If the selected tab is changed too quickly, the setPage is crashed and not work anymore // We apply throttle to prevent this issue https://github.com/Thinkei/hero-design/issues/1715 timeoutHandle = setTimeout(() => { // use no animation to prevent unexpected behavior if users select tab too quickly pagerViewRef.current?.setPageWithoutAnimation(selectedTabIndex); }, 200); } return () => { if (timeoutHandle) { clearTimeout(timeoutHandle); } }; }, [selectedTabIndex, pagerViewRef]); const tabContextProviderValue = useMemo( () => ({ selectedTabKey, }), [selectedTabKey] ); const headerProps = useMemo( () => ({ tabs, selectedIndex: selectedTabIndex, onTabPress, barStyle, insets, testID: componentTestID ? `${componentTestID}-tab-bar` : undefined, variant, }), [ tabs, selectedTabIndex, onTabPress, barStyle, insets, componentTestID, variant, ] ); return ( {header ? ( header(headerProps) ) : ( )} { const index = e.nativeEvent.position; const selectedItem = tabs[index]; if (hasScrolled.current && selectedItem) { setTimeout(() => { onTabPress(selectedItem.key); }); } }} scrollEnabled={swipeEnabled} style={{ flex: 1 }} > {tabs.map((tab, index) => { const { key, component, testID } = tab; return ( {component} ); })} ); }; export default ScrollableTab;