react-intersection-observer-hook
Version:
React hook to use IntersectionObserver declaratively.
155 lines (149 loc) • 5.18 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)(
({ newNode, newRoot }) => {
function cleanupObserver() {
const observer = observerRef.current;
const node = nodeRef.current;
if (node) {
observer?.unobserve(node);
setEntry(void 0);
}
observerRef.current = null;
}
function initializeObserver() {
if (!newNode) return;
const newObserver = observerCache.getObserver({
root: newRoot,
rootMargin,
threshold
});
newObserver.observe(newNode, (observedEntry) => {
setEntry(observedEntry);
});
observerRef.current = newObserver;
nodeRef.current = newNode;
rootRef.current = newRoot;
}
cleanupObserver();
initializeObserver();
},
[rootMargin, threshold]
);
const refCallback = (0, import_react.useCallback)(
(node) => {
reinitializeObserver({ newNode: node, newRoot: rootRef.current });
return () => {
reinitializeObserver({ newNode: null, newRoot: rootRef.current });
};
},
[reinitializeObserver]
);
const rootRefCallback = (0, import_react.useCallback)(
(rootNode) => {
reinitializeObserver({ newNode: nodeRef.current, newRoot: rootNode });
return () => {
reinitializeObserver({ newNode: nodeRef.current, newRoot: null });
};
},
[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
});