@gorhom/bottom-sheet
Version:
A performant interactive bottom sheet with fully configurable options 🚀
121 lines (116 loc) • 3.86 kB
JavaScript
import { useEffect, useRef } from 'react';
import { findNodeHandle } from 'react-native';
import { useSharedValue } from 'react-native-reanimated';
import { ANIMATION_STATE, SCROLLABLE_STATE } from '../constants';
import { useBottomSheetInternal } from './useBottomSheetInternal';
export const useScrollHandler = (_, onScroll) => {
//#region refs
const scrollableRef = useRef(null);
//#endregion
//#region variables
const scrollableContentOffsetY = useSharedValue(0);
//#endregion
//#region hooks
const {
animatedScrollableState,
animatedAnimationState,
animatedScrollableContentOffsetY
} = useBottomSheetInternal();
//#endregion
//#region effects
useEffect(() => {
// biome-ignore lint: to be addressed!
const element = findNodeHandle(scrollableRef.current);
let scrollOffset = 0;
let supportsPassive = false;
let maybePrevent = false;
let lastTouchY = 0;
let initialContentOffsetY = 0;
const shouldLockInitialPosition = false;
function handleOnTouchStart(event) {
if (event.touches.length !== 1) {
return;
}
initialContentOffsetY = element.scrollTop;
lastTouchY = event.touches[0].clientY;
maybePrevent = scrollOffset <= 0;
}
function handleOnTouchMove(event) {
if (animatedScrollableState.value === SCROLLABLE_STATE.LOCKED) {
return event.preventDefault();
}
if (maybePrevent) {
maybePrevent = false;
const touchY = event.touches[0].clientY;
const touchYDelta = touchY - lastTouchY;
if (touchYDelta > 0) {
return event.preventDefault();
}
}
return true;
}
function handleOnTouchEnd() {
if (animatedScrollableState.value === SCROLLABLE_STATE.LOCKED) {
const lockPosition = shouldLockInitialPosition ? initialContentOffsetY ?? 0 : 0;
element.scroll({
top: 0,
left: 0,
behavior: 'instant'
});
scrollableContentOffsetY.value = lockPosition;
return;
}
}
function handleOnScroll(event) {
scrollOffset = element.scrollTop;
if (animatedAnimationState.value !== ANIMATION_STATE.RUNNING) {
scrollableContentOffsetY.value = Math.max(0, scrollOffset);
animatedScrollableContentOffsetY.value = Math.max(0, scrollOffset);
}
if (scrollOffset <= 0) {
event.preventDefault();
event.stopPropagation();
return false;
}
return true;
}
try {
// @ts-ignore
window.addEventListener('test', null, {
// @ts-ignore
// biome-ignore lint: to be addressed
get passive() {
supportsPassive = true;
}
});
} catch (_e) {}
element.addEventListener('touchstart', handleOnTouchStart, supportsPassive ? {
passive: true
} : false);
element.addEventListener('touchmove', handleOnTouchMove, supportsPassive ? {
passive: false
} : false);
element.addEventListener('touchend', handleOnTouchEnd, supportsPassive ? {
passive: false
} : false);
element.addEventListener('scroll', handleOnScroll, supportsPassive ? {
passive: false
} : false);
return () => {
// @ts-ignore
window.removeEventListener('test', null);
element.removeEventListener('touchstart', handleOnTouchStart);
element.removeEventListener('touchmove', handleOnTouchMove);
element.removeEventListener('touchend', handleOnTouchEnd);
element.removeEventListener('scroll', handleOnScroll);
};
}, [animatedAnimationState, animatedScrollableContentOffsetY, animatedScrollableState, scrollableContentOffsetY]);
//#endregion
return {
scrollHandler: onScroll,
scrollableRef,
scrollableContentOffsetY
};
};
//# sourceMappingURL=useScrollHandler.web.js.map
;