Skip to main content
Glama
useScrollY.ts3.05 kB
'use client'; import { useCallback, useSyncExternalStore } from 'react'; import { useGetElementOrWindow } from './useGetElementOrWindow'; type UseScrollYProps = { element?: HTMLElement; }; type UseScrollYResult = { scrollY: number; scrollPercentage: number; scrollYMax: number; }; const INITIAL_SCROLL_STATE: UseScrollYResult = { scrollY: 0, scrollPercentage: 0, scrollYMax: 0, }; let lastSnapshot: UseScrollYResult = INITIAL_SCROLL_STATE; export const useScrollY = (props?: UseScrollYProps): UseScrollYResult => { const { element } = props ?? {}; const containerElement = useGetElementOrWindow(element); const subscribe = useCallback( (onChange: () => void) => { if (typeof window === 'undefined' || !containerElement) return () => {}; let raf = 0; const handler = () => { if (raf) return; raf = window.requestAnimationFrame(() => { raf = 0; onChange(); }); }; containerElement.addEventListener('scroll', handler, { passive: true }); return () => { containerElement.removeEventListener('scroll', handler); if (raf) window.cancelAnimationFrame(raf); }; }, [containerElement] ); const getSnapshot = (): UseScrollYResult => { if (typeof window === 'undefined' || !containerElement) { return INITIAL_SCROLL_STATE; // SSR/hydration-safe } // Handle custom element if (containerElement instanceof HTMLElement) { const scrollY = containerElement.scrollTop; const scrollHeight = containerElement.scrollHeight; const clientHeight = containerElement.clientHeight; const scrollYMax = Math.max(0, scrollHeight - clientHeight); const scrollPercentage = scrollYMax > 0 ? scrollY / scrollYMax : 0; if ( lastSnapshot.scrollY === scrollY && lastSnapshot.scrollPercentage === scrollPercentage && lastSnapshot.scrollYMax === scrollYMax ) { return lastSnapshot; } lastSnapshot = { scrollY, scrollPercentage, scrollYMax }; return lastSnapshot; } // Handle window const doc = document.documentElement; const body = document.body; const scrollY = window.scrollY ?? window.pageYOffset ?? doc?.scrollTop ?? body?.scrollTop ?? 0; const scrollHeight = doc?.scrollHeight ?? body?.scrollHeight ?? 0; const clientHeight = doc?.clientHeight ?? window.innerHeight ?? 0; const scrollYMax = Math.max(0, scrollHeight - clientHeight); const scrollPercentage = scrollYMax > 0 ? scrollY / scrollYMax : 0; if ( lastSnapshot.scrollY === scrollY && lastSnapshot.scrollPercentage === scrollPercentage && lastSnapshot.scrollYMax === scrollYMax ) { return lastSnapshot; } lastSnapshot = { scrollY, scrollPercentage, scrollYMax }; return lastSnapshot; }; const getServerSnapshot = (): UseScrollYResult => INITIAL_SCROLL_STATE; return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot); };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server