remix-utils-rt
Version:
This package contains simple utility functions to use with [React Router](https://reactrouter.com/home).
69 lines • 2.8 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import * as React from "react";
import { PrefetchPageLinks, useNavigate } from "react-router";
const context = React.createContext(false);
export function isLinkEvent(event) {
if (!(event.target instanceof HTMLElement))
return;
let a = event.target.closest("a");
if (a?.hasAttribute("href") && a.host === window.location.host)
return a;
return;
}
export function useDelegatedAnchors(nodeRef) {
let navigate = useNavigate();
let hasParentPrefetch = React.useContext(context);
React.useEffect(() => {
// if you call useDelegatedAnchors as a children of a PrefetchPageAnchors
// then do nothing
if (hasParentPrefetch)
return;
let node = nodeRef.current;
node?.addEventListener("click", handleClick);
return () => node?.removeEventListener("click", handleClick);
function handleClick(event) {
if (!node)
return;
let anchor = isLinkEvent(event);
if (!anchor)
return;
if (event.button !== 0)
return;
if (anchor.target && anchor.target !== "_self")
return;
if (event.metaKey || event.altKey || event.ctrlKey || event.shiftKey) {
return;
}
if (anchor.hasAttribute("download"))
return;
let { pathname, search, hash } = anchor;
navigate({ pathname, search, hash });
event.preventDefault();
}
}, [hasParentPrefetch, navigate, nodeRef]);
}
export function PrefetchPageAnchors({ children, }) {
let nodeRef = React.useRef(null);
let [page, setPage] = React.useState(null);
let hasParentPrefetch = React.useContext(context);
// prefetch is useless without delegated anchors, so we enable it
useDelegatedAnchors(nodeRef);
React.useEffect(() => {
if (hasParentPrefetch)
return;
let node = nodeRef.current;
node?.addEventListener("mouseenter", handleMouseEnter, true);
return () => node?.removeEventListener("mouseenter", handleMouseEnter);
function handleMouseEnter(event) {
if (!nodeRef.current)
return;
let anchor = isLinkEvent(event);
if (!anchor)
return;
let { pathname, search } = anchor;
setPage(pathname + search);
}
}, [hasParentPrefetch]);
return (_jsxs("div", { ref: nodeRef, style: { display: "contents" }, children: [_jsx(context.Provider, { value: true, children: children }), page && !hasParentPrefetch && _jsx(PrefetchPageLinks, { page: page })] }));
}
//# sourceMappingURL=use-delegated-anchors.js.map