@kentcdodds/tmp-remix-utils
Version:
This package contains simple utility functions to use with [Remix.run](https://remix.run).
64 lines (63 loc) • 2.4 kB
JavaScript
import { PrefetchPageLinks, useNavigate } from "@remix-run/react";
import * as React from "react";
const context = React.createContext(false);
export function isLinkEvent(event) {
if (!(event.target instanceof HTMLElement)) return;
let a = event.target.closest("a");
if (a && 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 React.createElement(
"div",
{ ref: nodeRef, style: { display: "contents" } },
React.createElement(context.Provider, { value: true }, children),
page &&
!hasParentPrefetch &&
React.createElement(PrefetchPageLinks, { page: page })
);
}