UNPKG

@attio/react-native-bottom-sheet-toolbox

Version:
91 lines (76 loc) 3.65 kB
import {PixelRatio} from "react-native" import {type SharedValue, useAnimatedReaction, useDerivedValue} from "react-native-reanimated" import {useBottomSheetToolboxInternalContext, useKeyboardProgressSharedValue} from "../context" import {useLastSharedValueBeforeLock} from "./use-last-shared-value-before-lock" export interface UseFooterBottomPositionSharedValueArgs { /** * A shared value that tells the footer how it should be moved with the * sheet. By default, this is the internal children height of the sheet. */ bufferSharedValue: SharedValue<number | null> /** * A shared value of the bottom position when the sheet was locked. */ bottomAtTimeOfLockSharedValue: SharedValue<number | null> } /** * Returns a shared value that tells the footer whether it should freeze its * position as the content is expanding. */ export function useFooterFreezeWhenExpanding({ bufferSharedValue, bottomAtTimeOfLockSharedValue, }: UseFooterBottomPositionSharedValueArgs) { const {currentPositionDestinationSharedValue} = useBottomSheetToolboxInternalContext() const keyboardProgressSharedValue = useKeyboardProgressSharedValue() const lastBufferSharedValue = useLastSharedValueBeforeLock(bufferSharedValue) const pixelRatio = PixelRatio.get() useAnimatedReaction( () => currentPositionDestinationSharedValue.get(), (destination, lastDestination) => { const lastBuffer = lastBufferSharedValue.get() if (lastBuffer !== null) { const destinationDiff = destination - (lastDestination ?? 0) const destinationDiffRounded = Math.round(destinationDiff * pixelRatio) / pixelRatio if (destinationDiffRounded < -1) { lastBufferSharedValue.set(bufferSharedValue.get()) } } }, [currentPositionDestinationSharedValue] ) const isExpandingSharedValue = useDerivedValue(() => { const buffer = bufferSharedValue.get() const lastBuffer = lastBufferSharedValue.get() const delta = buffer === null || lastBuffer === null ? null : buffer - lastBuffer return delta !== null && delta > 0 }, [lastBufferSharedValue, bufferSharedValue.get]) // This happens when opening and quickly closing. const wasMovingWithSheetSharedValue = useDerivedValue(() => { const bottomAtTimeOfLock = bottomAtTimeOfLockSharedValue.get() const roundedBottom = bottomAtTimeOfLock !== null ? Math.round(bottomAtTimeOfLock * pixelRatio) / pixelRatio : null return roundedBottom !== null && roundedBottom < 0 }, [bottomAtTimeOfLockSharedValue, pixelRatio]) const isKeyboardMovingSharedValue = useDerivedValue( () => keyboardProgressSharedValue.get() !== 0 && keyboardProgressSharedValue.get() !== 1, [keyboardProgressSharedValue] ) /** * If the content-size of the sheet increases, then we actually want the * footer to stay where it is (not shift down as if it's animating back in). * * * To determine this, we snapshot the sheet position at the time of the lock * and see if we're expanding up or down. We also keep a snapshot of the * bottom right before the lock was engaged. */ return useDerivedValue(() => { const wasMovingWithSheet = wasMovingWithSheetSharedValue.get() const isSettled = !wasMovingWithSheet && !isKeyboardMovingSharedValue.get() const isExpanding = isExpandingSharedValue.get() return isExpanding && isSettled }, []) }