diff options
author | dan <dan.abramov@gmail.com> | 2024-12-03 01:12:58 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-03 01:12:58 +0000 |
commit | 5a313c2d10b112458830b3bfc708031f6f8726a0 (patch) | |
tree | eb457935c5c9082ad091bc0a88e243c4a06215bc /src/view/com/pager/TabBar.tsx | |
parent | 996871d88ba3298ed53705a6c865cdfe5ede961a (diff) | |
download | voidsky-5a313c2d10b112458830b3bfc708031f6f8726a0.tar.zst |
[Nicer Tabs] Fork TabBar, simplify Pager (#6762)
* Fork TabBar.web.tsx * Trim dead code from both forks * Remove onPageSelecting event It's difficult to tell what exactly it's supposed to represent, and in practice it's not really used aside from logging. Let's rip it out for now to keep other changes simpler. * Remove early onPageSelected call It was added to try to do some work eagerly when we're sure which way the scroll is snapping. This is not necessarily a good idea though. It schedules a potentially expensive re-render right during the deceleration animation, which is not great. Whatever we're optimizing there, we should optimize smarter (e.g. prewarm just the network call). The other thing it used to help with is triggering the pager header autoscroll earlier. But we're going to rewrite that part differently anyway so that's not relevant either. * Prune more dead code from the native version We'll have to revisit this when adding tablet support but for now I'd prefer to remove a codepath that is not being tested or ever run. * Use regular ScrollView on native The Draggable thing was needed for web-only behavior so we can drop it in the native fork.
Diffstat (limited to 'src/view/com/pager/TabBar.tsx')
-rw-r--r-- | src/view/com/pager/TabBar.tsx | 102 |
1 files changed, 11 insertions, 91 deletions
diff --git a/src/view/com/pager/TabBar.tsx b/src/view/com/pager/TabBar.tsx index 4e8646c60..3f453971c 100644 --- a/src/view/com/pager/TabBar.tsx +++ b/src/view/com/pager/TabBar.tsx @@ -2,11 +2,8 @@ import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react' import {LayoutChangeEvent, ScrollView, StyleSheet, View} from 'react-native' import {usePalette} from '#/lib/hooks/usePalette' -import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' -import {isNative} from '#/platform/detection' import {PressableWithHover} from '../util/PressableWithHover' import {Text} from '../util/text/Text' -import {DraggableScrollView} from './DraggableScrollView' export interface TabBarProps { testID?: string @@ -31,68 +28,20 @@ export function TabBar({ }: TabBarProps) { const pal = usePalette('default') const scrollElRef = useRef<ScrollView>(null) - const itemRefs = useRef<Array<Element>>([]) const [itemXs, setItemXs] = useState<number[]>([]) const indicatorStyle = useMemo( () => ({borderBottomColor: indicatorColor || pal.colors.link}), [indicatorColor, pal], ) - const {isDesktop, isTablet} = useWebMediaQueries() - const styles = isDesktop || isTablet ? desktopStyles : mobileStyles useEffect(() => { - if (isNative) { - // On native, the primary interaction is swiping. - // We adjust the scroll little by little on every tab change. - // Scroll into view but keep the end of the previous item visible. - let x = itemXs[selectedPage] || 0 - x = Math.max(0, x - OFFSCREEN_ITEM_WIDTH) - scrollElRef.current?.scrollTo({x}) - } else { - // On the web, the primary interaction is tapping. - // Scrolling under tap feels disorienting so only adjust the scroll offset - // when tapping on an item out of view--and we adjust by almost an entire page. - const parent = scrollElRef?.current?.getScrollableNode?.() - if (!parent) { - return - } - const parentRect = parent.getBoundingClientRect() - if (!parentRect) { - return - } - const { - left: parentLeft, - right: parentRight, - width: parentWidth, - } = parentRect - const child = itemRefs.current[selectedPage] - if (!child) { - return - } - const childRect = child.getBoundingClientRect?.() - if (!childRect) { - return - } - const {left: childLeft, right: childRight, width: childWidth} = childRect - let dx = 0 - if (childRight >= parentRight) { - dx += childRight - parentRight - dx += parentWidth - childWidth - OFFSCREEN_ITEM_WIDTH - } else if (childLeft <= parentLeft) { - dx -= parentLeft - childLeft - dx -= parentWidth - childWidth - OFFSCREEN_ITEM_WIDTH - } - let x = parent.scrollLeft + dx - x = Math.max(0, x) - x = Math.min(x, parent.scrollWidth - parentWidth) - if (dx !== 0) { - parent.scroll({ - left: x, - behavior: 'smooth', - }) - } - } - }, [scrollElRef, itemXs, selectedPage, styles]) + // On native, the primary interaction is swiping. + // We adjust the scroll little by little on every tab change. + // Scroll into view but keep the end of the previous item visible. + let x = itemXs[selectedPage] || 0 + x = Math.max(0, x - OFFSCREEN_ITEM_WIDTH) + scrollElRef.current?.scrollTo({x}) + }, [scrollElRef, itemXs, selectedPage]) const onPressItem = useCallback( (index: number) => { @@ -122,7 +71,7 @@ export function TabBar({ testID={testID} style={[pal.view, styles.outer]} accessibilityRole="tablist"> - <DraggableScrollView + <ScrollView testID={`${testID}-selector`} horizontal={true} showsHorizontalScrollIndicator={false} @@ -134,7 +83,6 @@ export function TabBar({ <PressableWithHover testID={`${testID}-selector-${i}`} key={`${item}-${i}`} - ref={node => (itemRefs.current[i] = node as any)} onLayout={e => onItemLayout(e, i)} style={styles.item} hoverStyle={pal.viewLight} @@ -143,7 +91,7 @@ export function TabBar({ <View style={[styles.itemInner, selected && indicatorStyle]}> <Text emoji - type={isDesktop || isTablet ? 'xl-bold' : 'lg-bold'} + type="lg-bold" testID={testID ? `${testID}-${item}` : undefined} style={[ selected ? pal.text : pal.textLight, @@ -155,41 +103,13 @@ export function TabBar({ </PressableWithHover> ) })} - </DraggableScrollView> + </ScrollView> <View style={[pal.border, styles.outerBottomBorder]} /> </View> ) } -const desktopStyles = StyleSheet.create({ - outer: { - flexDirection: 'row', - width: 598, - }, - contentContainer: { - paddingHorizontal: 0, - backgroundColor: 'transparent', - }, - item: { - paddingTop: 14, - paddingHorizontal: 14, - justifyContent: 'center', - }, - itemInner: { - paddingBottom: 12, - borderBottomWidth: 3, - borderBottomColor: 'transparent', - }, - outerBottomBorder: { - position: 'absolute', - left: 0, - right: 0, - top: '100%', - borderBottomWidth: StyleSheet.hairlineWidth, - }, -}) - -const mobileStyles = StyleSheet.create({ +const styles = StyleSheet.create({ outer: { flexDirection: 'row', }, |