use-scroll.mjs 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839
  1. import { motionValue } from 'motion-dom';
  2. import { warning } from 'motion-utils';
  3. import { useEffect } from 'react';
  4. import { scroll } from '../render/dom/scroll/index.mjs';
  5. import { useConstant } from '../utils/use-constant.mjs';
  6. import { useIsomorphicLayoutEffect } from '../utils/use-isomorphic-effect.mjs';
  7. function refWarning(name, ref) {
  8. warning(Boolean(!ref || ref.current), `You have defined a ${name} options but the provided ref is not yet hydrated, probably because it's defined higher up the tree. Try calling useScroll() in the same component as the ref, or setting its \`layoutEffect: false\` option.`);
  9. }
  10. const createScrollMotionValues = () => ({
  11. scrollX: motionValue(0),
  12. scrollY: motionValue(0),
  13. scrollXProgress: motionValue(0),
  14. scrollYProgress: motionValue(0),
  15. });
  16. function useScroll({ container, target, layoutEffect = true, ...options } = {}) {
  17. const values = useConstant(createScrollMotionValues);
  18. const useLifecycleEffect = layoutEffect
  19. ? useIsomorphicLayoutEffect
  20. : useEffect;
  21. useLifecycleEffect(() => {
  22. refWarning("target", target);
  23. refWarning("container", container);
  24. return scroll((_progress, { x, y, }) => {
  25. values.scrollX.set(x.current);
  26. values.scrollXProgress.set(x.progress);
  27. values.scrollY.set(y.current);
  28. values.scrollYProgress.set(y.progress);
  29. }, {
  30. ...options,
  31. container: container?.current || undefined,
  32. target: target?.current || undefined,
  33. });
  34. }, [container, target, JSON.stringify(options.offset)]);
  35. return values;
  36. }
  37. export { useScroll };