index.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import { supportsScrollTimeline } from 'motion-dom';
  2. import { noop } from 'motion-utils';
  3. import { observeTimeline } from './observe.mjs';
  4. import { scrollInfo } from './track.mjs';
  5. function scrollTimelineFallback({ source, container, axis = "y", }) {
  6. // Support legacy source argument. Deprecate later.
  7. if (source)
  8. container = source;
  9. // ScrollTimeline records progress as a percentage CSSUnitValue
  10. const currentTime = { value: 0 };
  11. const cancel = scrollInfo((info) => {
  12. currentTime.value = info[axis].progress * 100;
  13. }, { container, axis });
  14. return { currentTime, cancel };
  15. }
  16. const timelineCache = new Map();
  17. function getTimeline({ source, container = document.documentElement, axis = "y", } = {}) {
  18. // Support legacy source argument. Deprecate later.
  19. if (source)
  20. container = source;
  21. if (!timelineCache.has(container)) {
  22. timelineCache.set(container, {});
  23. }
  24. const elementCache = timelineCache.get(container);
  25. if (!elementCache[axis]) {
  26. elementCache[axis] = supportsScrollTimeline()
  27. ? new ScrollTimeline({ source: container, axis })
  28. : scrollTimelineFallback({ source: container, axis });
  29. }
  30. return elementCache[axis];
  31. }
  32. /**
  33. * If the onScroll function has two arguments, it's expecting
  34. * more specific information about the scroll from scrollInfo.
  35. */
  36. function isOnScrollWithInfo(onScroll) {
  37. return onScroll.length === 2;
  38. }
  39. /**
  40. * Currently, we only support element tracking with `scrollInfo`, though in
  41. * the future we can also offer ViewTimeline support.
  42. */
  43. function needsElementTracking(options) {
  44. return options && (options.target || options.offset);
  45. }
  46. function scrollFunction(onScroll, options) {
  47. if (isOnScrollWithInfo(onScroll) || needsElementTracking(options)) {
  48. return scrollInfo((info) => {
  49. onScroll(info[options.axis].progress, info);
  50. }, options);
  51. }
  52. else {
  53. return observeTimeline(onScroll, getTimeline(options));
  54. }
  55. }
  56. function scrollAnimation(animation, options) {
  57. animation.flatten();
  58. if (needsElementTracking(options)) {
  59. animation.pause();
  60. return scrollInfo((info) => {
  61. animation.time = animation.duration * info[options.axis].progress;
  62. }, options);
  63. }
  64. else {
  65. const timeline = getTimeline(options);
  66. if (animation.attachTimeline) {
  67. return animation.attachTimeline(timeline, (valueAnimation) => {
  68. valueAnimation.pause();
  69. return observeTimeline((progress) => {
  70. valueAnimation.time = valueAnimation.duration * progress;
  71. }, timeline);
  72. });
  73. }
  74. else {
  75. return noop;
  76. }
  77. }
  78. }
  79. function scroll(onScroll, { axis = "y", ...options } = {}) {
  80. const optionsWithDefaults = { axis, ...options };
  81. return typeof onScroll === "function"
  82. ? scrollFunction(onScroll, optionsWithDefaults)
  83. : scrollAnimation(onScroll, optionsWithDefaults);
  84. }
  85. export { scroll };