UNPKG

@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
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 }) ); }