observers.mjs 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. /**
  2. * Map an IntersectionHandler callback to an element. We only ever make one handler for one
  3. * element, so even though these handlers might all be triggered by different
  4. * observers, we can keep them in the same map.
  5. */
  6. const observerCallbacks = new WeakMap();
  7. /**
  8. * Multiple observers can be created for multiple element/document roots. Each with
  9. * different settings. So here we store dictionaries of observers to each root,
  10. * using serialised settings (threshold/margin) as lookup keys.
  11. */
  12. const observers = new WeakMap();
  13. const fireObserverCallback = (entry) => {
  14. const callback = observerCallbacks.get(entry.target);
  15. callback && callback(entry);
  16. };
  17. const fireAllObserverCallbacks = (entries) => {
  18. entries.forEach(fireObserverCallback);
  19. };
  20. function initIntersectionObserver({ root, ...options }) {
  21. const lookupRoot = root || document;
  22. /**
  23. * If we don't have an observer lookup map for this root, create one.
  24. */
  25. if (!observers.has(lookupRoot)) {
  26. observers.set(lookupRoot, {});
  27. }
  28. const rootObservers = observers.get(lookupRoot);
  29. const key = JSON.stringify(options);
  30. /**
  31. * If we don't have an observer for this combination of root and settings,
  32. * create one.
  33. */
  34. if (!rootObservers[key]) {
  35. rootObservers[key] = new IntersectionObserver(fireAllObserverCallbacks, { root, ...options });
  36. }
  37. return rootObservers[key];
  38. }
  39. function observeIntersection(element, options, callback) {
  40. const rootInteresectionObserver = initIntersectionObserver(options);
  41. observerCallbacks.set(element, callback);
  42. rootInteresectionObserver.observe(element);
  43. return () => {
  44. observerCallbacks.delete(element);
  45. rootInteresectionObserver.unobserve(element);
  46. };
  47. }
  48. export { observeIntersection };