feat(ui): add useScrollHint hook for overflow containers

This commit is contained in:
alejandrobailo
2026-02-20 17:08:51 +01:00
parent 81f2ff915c
commit fea3649dd5
2 changed files with 64 additions and 0 deletions
+1
View File
@@ -3,6 +3,7 @@ export * from "./use-credentials-form";
export * from "./use-form-server-errors";
export * from "./use-local-storage";
export * from "./use-related-filters";
export * from "./use-scroll-hint";
export * from "./use-sidebar";
export * from "./use-store";
export * from "./use-url-filters";
+63
View File
@@ -0,0 +1,63 @@
"use client";
import { UIEvent, useEffect, useRef, useState } from "react";
interface UseScrollHintOptions {
enabled?: boolean;
refreshToken?: string | number;
}
const SCROLL_THRESHOLD_PX = 2;
function shouldShowScrollHint(element: HTMLDivElement) {
const hasOverflow =
element.scrollHeight - element.clientHeight > SCROLL_THRESHOLD_PX;
const isAtBottom =
element.scrollTop + element.clientHeight >=
element.scrollHeight - SCROLL_THRESHOLD_PX;
return hasOverflow && !isAtBottom;
}
export function useScrollHint({
enabled = true,
refreshToken,
}: UseScrollHintOptions = {}) {
const containerRef = useRef<HTMLDivElement | null>(null);
const [showScrollHint, setShowScrollHint] = useState(false);
useEffect(() => {
if (!enabled) {
setShowScrollHint(false);
return;
}
const frame = requestAnimationFrame(() => {
const element = containerRef.current;
if (!element) return;
setShowScrollHint(shouldShowScrollHint(element));
});
const handleResize = () => {
const element = containerRef.current;
if (!element) return;
setShowScrollHint(shouldShowScrollHint(element));
};
window.addEventListener("resize", handleResize);
return () => {
cancelAnimationFrame(frame);
window.removeEventListener("resize", handleResize);
};
}, [enabled, refreshToken]);
const handleScroll = (event: UIEvent<HTMLDivElement>) => {
setShowScrollHint(shouldShowScrollHint(event.currentTarget));
};
return {
containerRef,
showScrollHint,
handleScroll,
};
}