diff --git a/src/components/TabSelector/TabSelectorContext.tsx b/src/components/TabSelector/TabSelectorContext.tsx index 20135228d149f..adff7d56693a0 100644 --- a/src/components/TabSelector/TabSelectorContext.tsx +++ b/src/components/TabSelector/TabSelectorContext.tsx @@ -1,6 +1,6 @@ import React, {createContext, useRef} from 'react'; // eslint-disable-next-line no-restricted-imports -import type {LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, ScrollView as RNScrollView, View} from 'react-native'; +import type {LayoutChangeEvent, NativeScrollEvent, NativeSyntheticEvent, ScrollView as RNScrollView} from 'react-native'; import scrollToTabUtil from './scrollToTab'; type TabSelectorContextValue = { @@ -8,7 +8,6 @@ type TabSelectorContextValue = { onContainerLayout: (event: LayoutChangeEvent) => void; onContainerScroll: (event: NativeSyntheticEvent) => void; scrollToTab: (tabKey: string) => void; - registerTab: (tabKey: string, ref: HTMLDivElement | View | null) => void; onTabLayout: (tabKey: string, event: LayoutChangeEvent) => void; }; @@ -22,7 +21,6 @@ const defaultValue: TabSelectorContextValue = { onContainerLayout: () => {}, onContainerScroll: () => {}, scrollToTab: () => {}, - registerTab: () => {}, onTabLayout: () => {}, }; @@ -31,33 +29,36 @@ const TabSelectorContext = createContext(defaultValue); function TabSelectorContextProvider({children, activeTabKey}: TabSelectorContextProviderProps) { const containerRef = useRef(null); const containerLayoutRef = useRef<{x: number; width: number}>({x: 0, width: 0}); - const tabsRef = useRef>({}); + const tabsRef = useRef>({}); const onContainerLayout = (event: LayoutChangeEvent) => { const width = event.nativeEvent.layout.width; containerLayoutRef.current.width = width; - }; - const onContainerScroll = (event: NativeSyntheticEvent) => { - const x = event.nativeEvent.contentOffset.x; - containerLayoutRef.current.x = x; - }; + const tabData = tabsRef.current[activeTabKey]; - const registerTab = (tabKey: string, ref: HTMLDivElement | View | null) => { - if (ref === null) { + if (!tabData) { return; } - tabsRef.current[tabKey] = {...tabsRef.current[tabKey], ref}; + const {x: tabX, width: tabWidth} = tabData; + + if (tabWidth) { + scrollToTabUtil({tabX, tabWidth, containerRef, containerWidth: containerLayoutRef.current.width, containerX: containerLayoutRef.current.x, animated: false}); + } + }; + + const onContainerScroll = (event: NativeSyntheticEvent) => { + const x = event.nativeEvent.contentOffset.x; + containerLayoutRef.current.x = x; }; const onTabLayout = (tabKey: string, event: LayoutChangeEvent) => { const {x, width} = event.nativeEvent.layout; tabsRef.current[tabKey] = {...tabsRef.current[tabKey], x, width}; - if (tabKey === activeTabKey) { - const {ref: tabRef} = tabsRef.current[tabKey]; - scrollToTabUtil({tabX: x, tabWidth: width, tabRef, containerRef, containerWidth: containerLayoutRef.current.width, containerX: containerLayoutRef.current.x, animated: false}); + if (tabKey === activeTabKey && containerLayoutRef.current.width !== 0) { + scrollToTabUtil({tabX: x, tabWidth: width, containerRef, containerWidth: containerLayoutRef.current.width, containerX: containerLayoutRef.current.x, animated: false}); } }; @@ -68,16 +69,15 @@ function TabSelectorContextProvider({children, activeTabKey}: TabSelectorContext return; } - const {x: tabX, width: tabWidth, ref: tabRef} = tabData; + const {x: tabX, width: tabWidth} = tabData; - scrollToTabUtil({tabX, tabWidth, tabRef, containerRef, containerWidth: containerLayoutRef.current.width, containerX: containerLayoutRef.current.x}); + scrollToTabUtil({tabX, tabWidth, containerRef, containerWidth: containerLayoutRef.current.width, containerX: containerLayoutRef.current.x}); }; // React Compiler auto-memoization // eslint-disable-next-line react/jsx-no-constructed-context-values const contextValue = { containerRef, - registerTab, onTabLayout, onContainerLayout, onContainerScroll, diff --git a/src/components/TabSelector/TabSelectorItem.tsx b/src/components/TabSelector/TabSelectorItem.tsx index 0b6c290736bc8..38050d80a54c8 100644 --- a/src/components/TabSelector/TabSelectorItem.tsx +++ b/src/components/TabSelector/TabSelectorItem.tsx @@ -1,7 +1,6 @@ import React, {useContext, useState} from 'react'; // eslint-disable-next-line no-restricted-imports import {Animated} from 'react-native'; -import type {View} from 'react-native'; import PressableWithFeedback from '@components/Pressable/PressableWithFeedback'; import Tooltip from '@components/Tooltip'; import EducationalTooltip from '@components/Tooltip/EducationalTooltip'; @@ -37,13 +36,12 @@ function TabSelectorItem({ const [isHovered, setIsHovered] = useState(false); const shouldShowEducationalTooltip = shouldShowProductTrainingTooltip && isActive; - const {onTabLayout, registerTab, scrollToTab} = useContext(TabSelectorContext); + const {onTabLayout, scrollToTab} = useContext(TabSelectorContext); const accessibilityState = {selected: isActive}; const children = ( registerTab(tabKey, ref)} accessibilityLabel={title} accessibilityState={accessibilityState} accessibilityRole={CONST.ROLE.TAB} diff --git a/src/components/TabSelector/scrollToTab/index.native.ts b/src/components/TabSelector/scrollToTab/index.native.ts deleted file mode 100644 index cf0c3f3b106e5..0000000000000 --- a/src/components/TabSelector/scrollToTab/index.native.ts +++ /dev/null @@ -1,24 +0,0 @@ -import variables from '@styles/variables'; -import type {ScrollToTabProps} from './types'; - -function scrollToTab({containerX, tabX, tabWidth, animated = true, containerRef, containerWidth}: ScrollToTabProps) { - if (!containerRef.current) { - return; - } - - const isTabLeftSideCut = containerX > tabX; - const isTabRightSideCut = tabX + tabWidth >= containerX + containerWidth - variables.tabSelectorScrollMarginInline; - if (!isTabLeftSideCut && !isTabRightSideCut) { - return; - } - - if (isTabRightSideCut) { - const tabCutLengthOnRight = tabX + tabWidth - (containerWidth + containerX); - containerRef.current.scrollTo({x: containerX + tabCutLengthOnRight + variables.tabSelectorScrollMarginInline, animated}); - return; - } - - containerRef.current.scrollTo({x: tabX - variables.tabSelectorScrollMarginInline, animated}); -} - -export default scrollToTab; diff --git a/src/components/TabSelector/scrollToTab/index.ts b/src/components/TabSelector/scrollToTab/index.ts index 4899a01c01b87..2c048c222e4a6 100644 --- a/src/components/TabSelector/scrollToTab/index.ts +++ b/src/components/TabSelector/scrollToTab/index.ts @@ -1,11 +1,25 @@ +import variables from '@styles/variables'; import type {ScrollToTabProps} from './types'; -function scrollToTab({tabRef, animated = true}: ScrollToTabProps) { - if (!tabRef || !('scrollIntoView' in tabRef)) { +function scrollToTab({containerX, tabX, tabWidth, animated = true, containerRef, containerWidth}: ScrollToTabProps) { + if (!containerRef.current) { return; } - tabRef.scrollIntoView({block: 'nearest', behavior: animated ? 'smooth' : 'instant'}); + const isTabLeftSideCut = containerX > tabX; + const isTabRightSideCut = tabX + tabWidth >= containerX + containerWidth - variables.tabSelectorScrollMarginInline; + + if (!isTabLeftSideCut && !isTabRightSideCut) { + return; + } + + if (isTabRightSideCut) { + const tabCutLengthOnRight = tabX + tabWidth - (containerWidth + containerX); + containerRef.current.scrollTo({x: containerX + tabCutLengthOnRight + variables.tabSelectorScrollMarginInline, animated}); + return; + } + + containerRef.current.scrollTo({x: tabX - variables.tabSelectorScrollMarginInline, animated}); } export default scrollToTab; diff --git a/src/components/TabSelector/scrollToTab/types.ts b/src/components/TabSelector/scrollToTab/types.ts index 5aaa949f04ab1..d170ee0a1ea26 100644 --- a/src/components/TabSelector/scrollToTab/types.ts +++ b/src/components/TabSelector/scrollToTab/types.ts @@ -1,9 +1,8 @@ // eslint-disable-next-line no-restricted-imports -import type {ScrollView as RNScrollView, View} from 'react-native'; +import type {ScrollView as RNScrollView} from 'react-native'; type ScrollToTabProps = { animated?: boolean; - tabRef: HTMLDivElement | View | null; containerRef: React.RefObject; containerX: number; containerWidth: number;