UNPKG

@mantine/hooks

Version:

A collection of 50+ hooks for state and UI management

76 lines (75 loc) 3.47 kB
"use client"; import { useIsomorphicEffect } from "../use-isomorphic-effect/use-isomorphic-effect.mjs"; import { useWindowScroll } from "../use-window-scroll/use-window-scroll.mjs"; import { useScrollDirection } from "../use-scroll-direction/use-scroll-direction.mjs"; import { useEffectEvent, useRef } from "react"; //#region packages/@mantine/hooks/src/use-headroom/use-headroom.ts const isFixed = (current, fixedAt) => current <= fixedAt; const isPinnedOrReleased = (current, fixedAt, isCurrentlyPinnedRef, isScrollingUp, onPin, onRelease) => { const isInFixedPosition = isFixed(current, fixedAt); if (isInFixedPosition && !isCurrentlyPinnedRef.current) { isCurrentlyPinnedRef.current = true; onPin?.(); } else if (!isInFixedPosition && isScrollingUp && !isCurrentlyPinnedRef.current) { isCurrentlyPinnedRef.current = true; onPin?.(); } else if (!isInFixedPosition && !isScrollingUp && isCurrentlyPinnedRef.current) { isCurrentlyPinnedRef.current = false; onRelease?.(); } }; function useHeadroom({ fixedAt = 0, scrollDistance = 100, onPin, onFix, onRelease } = {}) { const isCurrentlyPinnedRef = useRef(false); const isScrollingUp = useScrollDirection() === "up"; const [{ y: scrollPosition }] = useWindowScroll(); const onPinEvent = useEffectEvent(() => onPin?.()); const onReleaseEvent = useEffectEvent(() => onRelease?.()); const onFixEvent = useEffectEvent(() => onFix?.()); useIsomorphicEffect(() => { isPinnedOrReleased(scrollPosition, fixedAt, isCurrentlyPinnedRef, isScrollingUp, onPinEvent, onReleaseEvent); }, [ scrollPosition, fixedAt, isScrollingUp ]); useIsomorphicEffect(() => { if (isFixed(scrollPosition, fixedAt)) onFixEvent(); }, [scrollPosition, fixedAt]); const currentlyFixed = isFixed(scrollPosition, fixedAt); const prevIsFixedRef = useRef(currentlyFixed); const directionChangeScrollYRef = useRef(scrollPosition); const progressAtDirectionChangeRef = useRef(currentlyFixed ? 1 : 0); const prevIsScrollingUpRef = useRef(isScrollingUp); if (prevIsFixedRef.current !== currentlyFixed) { prevIsFixedRef.current = currentlyFixed; if (!currentlyFixed) { directionChangeScrollYRef.current = fixedAt; progressAtDirectionChangeRef.current = 1; } else { directionChangeScrollYRef.current = scrollPosition; progressAtDirectionChangeRef.current = 1; } prevIsScrollingUpRef.current = isScrollingUp; } if (!currentlyFixed && prevIsScrollingUpRef.current !== isScrollingUp) { const transitionDelta = Math.abs(scrollPosition - directionChangeScrollYRef.current); const transitionProgress = prevIsScrollingUpRef.current ? Math.min(progressAtDirectionChangeRef.current + transitionDelta / scrollDistance, 1) : Math.max(progressAtDirectionChangeRef.current - transitionDelta / scrollDistance, 0); prevIsScrollingUpRef.current = isScrollingUp; directionChangeScrollYRef.current = scrollPosition; progressAtDirectionChangeRef.current = transitionProgress; } let scrollProgress; if (currentlyFixed) scrollProgress = 1; else { const scrollDelta = Math.abs(scrollPosition - directionChangeScrollYRef.current); if (isScrollingUp) scrollProgress = Math.min(progressAtDirectionChangeRef.current + scrollDelta / scrollDistance, 1); else scrollProgress = Math.max(progressAtDirectionChangeRef.current - scrollDelta / scrollDistance, 0); } return { pinned: scrollProgress > 0, scrollProgress }; } //#endregion export { useHeadroom }; //# sourceMappingURL=use-headroom.mjs.map