react-intersection-observer-hook
Version:
React hook to use IntersectionObserver declaratively.
155 lines (149 loc) • 5.01 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
useIntersectionObserver: () => use_intersection_observer_default,
useTrackVisibility: () => use_track_visibility_default
});
module.exports = __toCommonJS(src_exports);
// src/use-intersection-observer.ts
var import_react = require("react");
// src/utils.ts
function createObserverCache() {
const cachesByRoot = /* @__PURE__ */ new Map();
function getObserver({
root,
rootMargin,
threshold
}) {
let cacheByRoot = cachesByRoot.get(root);
if (!cacheByRoot) {
cacheByRoot = /* @__PURE__ */ new Map();
cachesByRoot.set(root, cacheByRoot);
}
const cacheKey = JSON.stringify({ rootMargin, threshold });
let cachedObserver = cacheByRoot.get(cacheKey);
if (!cachedObserver) {
const entryCallbacks = /* @__PURE__ */ new Map();
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
const callback = entryCallbacks.get(entry.target);
callback?.(entry);
});
},
{ root, rootMargin, threshold }
);
cachedObserver = { observer, entryCallbacks };
cacheByRoot.set(cacheKey, cachedObserver);
}
return {
observe: (node, callback) => {
cachedObserver.entryCallbacks.set(node, callback);
cachedObserver.observer.observe(node);
},
unobserve: (node) => {
cachedObserver.entryCallbacks.delete(node);
cachedObserver.observer.unobserve(node);
}
};
}
return { getObserver };
}
// src/use-intersection-observer.ts
var DEFAULT_ROOT_MARGIN = "0px";
var DEFAULT_THRESHOLD = [0];
var observerCache = createObserverCache();
function useIntersectionObserver(args) {
const rootMargin = args?.rootMargin ?? DEFAULT_ROOT_MARGIN;
const threshold = args?.threshold ?? DEFAULT_THRESHOLD;
const nodeRef = (0, import_react.useRef)(null);
const rootRef = (0, import_react.useRef)(null);
const observerRef = (0, import_react.useRef)(null);
const [entry, setEntry] = (0, import_react.useState)();
const reinitializeObserver = (0, import_react.useCallback)(() => {
function cleanupObserver() {
const observer = observerRef.current;
const node = nodeRef.current;
if (node) {
observer?.unobserve(node);
setEntry(void 0);
}
observerRef.current = null;
}
function initializeObserver() {
const node = nodeRef.current;
if (!node) return;
const observer = observerCache.getObserver({
root: rootRef.current,
rootMargin,
threshold
});
observer.observe(node, (observedEntry) => {
setEntry(observedEntry);
});
observerRef.current = observer;
}
cleanupObserver();
initializeObserver();
}, [rootMargin, threshold]);
const refCallback = (0, import_react.useCallback)(
(node) => {
nodeRef.current = node;
reinitializeObserver();
return () => {
nodeRef.current = null;
reinitializeObserver();
};
},
[reinitializeObserver]
);
const rootRefCallback = (0, import_react.useCallback)(
(rootNode) => {
rootRef.current = rootNode;
reinitializeObserver();
return () => {
rootRef.current = null;
reinitializeObserver();
};
},
[reinitializeObserver]
);
return [refCallback, { entry, rootRef: rootRefCallback }];
}
var use_intersection_observer_default = useIntersectionObserver;
// src/use-track-visibility.ts
var import_react2 = require("react");
function useTrackVisibility(args) {
const { once, ...rest } = args ?? {};
const [ref, result] = use_intersection_observer_default(rest);
const isVisible = Boolean(result.entry?.isIntersecting);
const [isVisibleOnce, setIsVisibleOnce] = (0, import_react2.useState)(isVisible);
if (once && isVisible && !isVisibleOnce) {
setIsVisibleOnce(true);
}
return [ref, { ...result, isVisible: once ? isVisibleOnce : isVisible }];
}
var use_track_visibility_default = useTrackVisibility;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
useIntersectionObserver,
useTrackVisibility
});
;