UNPKG

rwsdk

Version:

Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime

89 lines (88 loc) 2.75 kB
function saveScrollPosition(x, y) { window.history.replaceState({ ...window.history.state, scrollX: x, scrollY: y, }, "", window.location.href); } export function validateClickEvent(event, target) { // should this only work for left click? if (event.button !== 0) { return false; } if (event.ctrlKey || event.metaKey || event.shiftKey || event.altKey) { return false; } const link = target.closest("a"); if (!link) { return false; } const href = link.getAttribute("href"); if (!href) { return false; } if (href.includes("#")) { return false; } // Skip if target="_blank" or similar if (link.target && link.target !== "_self") { return false; } if (href.startsWith("http")) { return false; } // Skip if download attribute if (link.hasAttribute("download")) { return false; } return true; } export function initClientNavigation(opts = {}) { const options = { onNavigate: async function onNavigate() { // @ts-expect-error await globalThis.__rsc_callServer(); }, scrollToTop: true, scrollBehavior: "instant", ...opts, }; history.scrollRestoration = "auto"; document.addEventListener("click", async function handleClickEvent(event) { // Prevent default navigation if (!validateClickEvent(event, event.target)) { return; } event.preventDefault(); const el = event.target; const a = el.closest("a"); const href = a?.getAttribute("href"); saveScrollPosition(window.scrollX, window.scrollY); window.history.pushState({ path: href }, "", window.location.origin + href); await options.onNavigate(); if (options.scrollToTop && history.scrollRestoration === "auto") { window.scrollTo({ top: 0, left: 0, behavior: options.scrollBehavior, }); saveScrollPosition(0, 0); } history.scrollRestoration = "auto"; }, true); window.addEventListener("popstate", async function handlePopState() { saveScrollPosition(window.scrollX, window.scrollY); await options.onNavigate(); }); // Return a handleResponse function for use with initClient return { handleResponse: function handleResponse(response) { if (!response.ok) { // Redirect to the current page (window.location) to show the error window.location.href = window.location.href; return false; } return true; }, }; }