@attio/react-native-bottom-sheet-toolbox
Version:
80 lines (76 loc) • 3.37 kB
JavaScript
;
import { useAnimatedReaction, useSharedValue } from "react-native-reanimated";
import { useBottomSheetToolboxInternalContext } from "../context";
import { BottomSheetPositionBuiltInLockPriority, snapPoint } from "../utils";
import { useBottomSheetPositionLock } from "./use-bottom-sheet-position-lock";
const LOCK_ID = "useBottomSheetSnapWhenIdle";
/**
* This hook snaps the bottom sheet to the nearest snap point when
* nothing else is interacting with it. It takes into account the
* last known velocity.
*
* A snap is triggered after either of the following two conditions:
* - The position off any snap-point, and has been released.
* - The underlying snap-points have changed.
*/
export function useBottomSheetSnapWhenIdle() {
const {
currentPositionSharedValue,
currentPositionLastVelocitySharedValue,
currentPositionDestinationSharedValue,
normalizedSnapPointsSharedValue,
isReadySharedValue,
currentPositionLockSharedValue
} = useBottomSheetToolboxInternalContext();
const {
canLockSharedValue,
hasLockSharedValue,
lock,
release,
setPositionAnimate,
setVelocity
} = useBottomSheetPositionLock(LOCK_ID, BottomSheetPositionBuiltInLockPriority.SNAP_WHEN_IDLE);
const lastSnapPointIndexSharedValue = useSharedValue(-1);
useAnimatedReaction(() => ({
canLock: isReadySharedValue.get() && canLockSharedValue.get(),
hasLock: hasLockSharedValue.get(),
snapPoints: normalizedSnapPointsSharedValue.get()
}), ({
canLock,
hasLock,
snapPoints
}, lastResults) => {
const canLockOrHasLock = canLock || hasLock;
if (!snapPoints || !canLockOrHasLock) {
lastSnapPointIndexSharedValue.set(-1);
return;
}
const lastCanLockOrHasLock = lastResults?.canLock || lastResults?.hasLock;
const didLockStatusChange = lastCanLockOrHasLock !== canLockOrHasLock;
const lastSnapPoints = lastResults?.snapPoints || [];
const didSnapPointsChange = snapPoints === null ? lastSnapPoints === null : lastSnapPoints.length !== snapPoints.length || lastSnapPoints.some((v, index) => v !== snapPoints[index]);
// Nothing to do
if (!didLockStatusChange && !didSnapPointsChange) return;
/**
* If our snap-points change, then try to follow the snap-point we
* were last at. This also supports the case where the snap-points
* are updated to be equal, but then separate again. That case can
* happen when the keyboard opens.
*/
lastSnapPointIndexSharedValue.set(lastSnapPoints.indexOf(currentPositionDestinationSharedValue.get()));
const currentPosition = currentPositionSharedValue.get();
const point = lastSnapPointIndexSharedValue.get() === -1 ? snapPoint(currentPosition, currentPositionLastVelocitySharedValue.get(), snapPoints) : snapPoints[lastSnapPointIndexSharedValue.get()] ?? null;
if (point === null || point === currentPosition) return;
if (!hasLock) {
lock();
}
setPositionAnimate(point, undefined, finished => {
const currentPositionLock = currentPositionLockSharedValue.get();
if (finished || currentPositionLock?.id !== LOCK_ID) {
release();
}
});
setVelocity(0);
}, [canLockSharedValue, hasLockSharedValue, normalizedSnapPointsSharedValue, isReadySharedValue.get]);
}
//# sourceMappingURL=use-bottom-sheet-snap-when-idle.js.map