diff options
Diffstat (limited to 'src/view/com')
-rw-r--r-- | src/view/com/pager/PagerHeaderContext.tsx | 30 | ||||
-rw-r--r-- | src/view/com/pager/PagerWithHeader.tsx | 25 | ||||
-rw-r--r-- | src/view/com/pager/PagerWithHeader.web.tsx | 16 |
3 files changed, 52 insertions, 19 deletions
diff --git a/src/view/com/pager/PagerHeaderContext.tsx b/src/view/com/pager/PagerHeaderContext.tsx index fd4cc7463..c979f7a6d 100644 --- a/src/view/com/pager/PagerHeaderContext.tsx +++ b/src/view/com/pager/PagerHeaderContext.tsx @@ -1,40 +1,48 @@ import React, {useContext} from 'react' import {SharedValue} from 'react-native-reanimated' -import {isIOS} from '#/platform/detection' +import {isNative} from '#/platform/detection' -export const PagerHeaderContext = - React.createContext<SharedValue<number> | null>(null) +export const PagerHeaderContext = React.createContext<{ + scrollY: SharedValue<number> + headerHeight: number +} | null>(null) /** - * Passes the scrollY value to the pager header's banner, so it can grow on - * overscroll on iOS. Not necessary to use this context provider on other platforms. + * Passes information about the scroll position and header height down via + * context for the pager header to consume. * - * @platform ios + * @platform ios, android */ export function PagerHeaderProvider({ scrollY, + headerHeight, children, }: { scrollY: SharedValue<number> + headerHeight: number children: React.ReactNode }) { + const value = React.useMemo( + () => ({scrollY, headerHeight}), + [scrollY, headerHeight], + ) return ( - <PagerHeaderContext.Provider value={scrollY}> + <PagerHeaderContext.Provider value={value}> {children} </PagerHeaderContext.Provider> ) } export function usePagerHeaderContext() { - const scrollY = useContext(PagerHeaderContext) - if (isIOS) { - if (!scrollY) { + const ctx = useContext(PagerHeaderContext) + if (isNative) { + if (!ctx) { throw new Error( 'usePagerHeaderContext must be used within a HeaderProvider', ) } - return {scrollY} + return ctx } else { return null } diff --git a/src/view/com/pager/PagerWithHeader.tsx b/src/view/com/pager/PagerWithHeader.tsx index 617445964..dcf141f84 100644 --- a/src/view/com/pager/PagerWithHeader.tsx +++ b/src/view/com/pager/PagerWithHeader.tsx @@ -38,7 +38,11 @@ export interface PagerWithHeaderProps { | ((props: PagerWithHeaderChildParams) => JSX.Element) items: string[] isHeaderReady: boolean - renderHeader?: () => JSX.Element + renderHeader?: ({ + setMinimumHeight, + }: { + setMinimumHeight: (height: number) => void + }) => JSX.Element initialPage?: number onPageSelected?: (index: number) => void onCurrentPageSelected?: (index: number) => void @@ -83,7 +87,9 @@ export const PagerWithHeader = React.forwardRef<PagerRef, PagerWithHeaderProps>( const renderTabBar = React.useCallback( (props: RenderTabBarFnProps) => { return ( - <PagerHeaderProvider scrollY={scrollY}> + <PagerHeaderProvider + scrollY={scrollY} + headerHeight={headerOnlyHeight}> <PagerTabBar headerOnlyHeight={headerOnlyHeight} items={items} @@ -237,7 +243,11 @@ let PagerTabBar = ({ items: string[] testID?: string scrollY: SharedValue<number> - renderHeader?: () => JSX.Element + renderHeader?: ({ + setMinimumHeight, + }: { + setMinimumHeight: (height: number) => void + }) => JSX.Element onHeaderOnlyLayout: (height: number) => void onTabBarLayout: (e: LayoutChangeEvent) => void onCurrentPageSelected?: (index: number) => void @@ -246,8 +256,13 @@ let PagerTabBar = ({ dragProgress: SharedValue<number> dragState: SharedValue<'idle' | 'dragging' | 'settling'> }): React.ReactNode => { + const [minimumHeaderHeight, setMinimumHeaderHeight] = React.useState(0) const headerTransform = useAnimatedStyle(() => { - const translateY = Math.min(scrollY.get(), headerOnlyHeight) * -1 + const translateY = + Math.min( + scrollY.get(), + Math.max(headerOnlyHeight - minimumHeaderHeight, 0), + ) * -1 return { transform: [ { @@ -267,7 +282,7 @@ let PagerTabBar = ({ ref={headerRef} pointerEvents={isIOS ? 'auto' : 'box-none'} collapsable={false}> - {renderHeader?.()} + {renderHeader?.({setMinimumHeight: setMinimumHeaderHeight})} { // It wouldn't be enough to place `onLayout` on the parent node because // this would risk measuring before `isHeaderReady` has turned `true`. diff --git a/src/view/com/pager/PagerWithHeader.web.tsx b/src/view/com/pager/PagerWithHeader.web.tsx index 3335532b3..98b32b347 100644 --- a/src/view/com/pager/PagerWithHeader.web.tsx +++ b/src/view/com/pager/PagerWithHeader.web.tsx @@ -21,7 +21,11 @@ export interface PagerWithHeaderProps { | ((props: PagerWithHeaderChildParams) => JSX.Element) items: string[] isHeaderReady: boolean - renderHeader?: () => JSX.Element + renderHeader?: ({ + setMinimumHeight, + }: { + setMinimumHeight: () => void + }) => JSX.Element initialPage?: number onPageSelected?: (index: number) => void onCurrentPageSelected?: (index: number) => void @@ -115,7 +119,11 @@ let PagerTabBar = ({ currentPage: number items: string[] testID?: string - renderHeader?: () => JSX.Element + renderHeader?: ({ + setMinimumHeight, + }: { + setMinimumHeight: () => void + }) => JSX.Element isHeaderReady: boolean onCurrentPageSelected?: (index: number) => void onSelect?: (index: number) => void @@ -123,7 +131,7 @@ let PagerTabBar = ({ }): React.ReactNode => { return ( <> - <Layout.Center>{renderHeader?.()}</Layout.Center> + <Layout.Center>{renderHeader?.({setMinimumHeight: noop})}</Layout.Center> {tabBarAnchor} <Layout.Center style={web([ @@ -175,3 +183,5 @@ function toArray<T>(v: T | T[]): T[] { } return [v] } + +function noop() {} |