useVirtualScrolling.tsx 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import type {RefObject} from 'react';
  2. import {useCallback, useEffect, useState} from 'react';
  3. import clamp from 'sentry/utils/number/clamp';
  4. interface Props<Element extends HTMLElement> {
  5. contentRef: RefObject<Element>;
  6. windowRef: RefObject<Element>;
  7. }
  8. export default function useVirtualScrolling<Element extends HTMLElement>({
  9. contentRef,
  10. windowRef,
  11. }: Props<Element>) {
  12. const window = windowRef.current;
  13. const content = contentRef.current;
  14. const [scrollPosition, setScrollPosition] = useState({
  15. offsetX: 0,
  16. offsetY: 0,
  17. });
  18. const reclamp = useCallback(() => {
  19. if (!window) {
  20. return;
  21. }
  22. setScrollPosition(prev => {
  23. const minX =
  24. (content?.clientWidth ?? Number.MAX_SAFE_INTEGER) * -1 + window.clientWidth;
  25. const minY =
  26. (content?.clientHeight ?? Number.MAX_SAFE_INTEGER) * -1 + window.clientHeight;
  27. const offsetX = clamp(prev.offsetX, minX, 0);
  28. const offsetY = clamp(prev.offsetY, minY, 0);
  29. return {offsetX, offsetY};
  30. });
  31. }, [content, window]);
  32. useEffect(() => {
  33. if (!window) {
  34. return () => {};
  35. }
  36. const handleWheel = (e: WheelEvent) => {
  37. const {deltaX, deltaY} = e;
  38. setScrollPosition(prev => {
  39. const minX =
  40. (content?.clientWidth ?? Number.MAX_SAFE_INTEGER) * -1 + window.clientWidth;
  41. const minY =
  42. (content?.clientHeight ?? Number.MAX_SAFE_INTEGER) * -1 + window.clientHeight;
  43. const offsetX = clamp(prev.offsetX - deltaX, minX, 0);
  44. const offsetY = clamp(prev.offsetY - deltaY, minY, 0);
  45. return {offsetX, offsetY};
  46. });
  47. };
  48. window.addEventListener('wheel', handleWheel);
  49. return () => {
  50. window.removeEventListener('wheel', handleWheel);
  51. };
  52. }, [content, window]);
  53. return {
  54. ...scrollPosition,
  55. reclamp,
  56. };
  57. }