UNPKG

blade

Version:
85 lines (83 loc) 3.91 kB
import { _ as RootClientContext, c as usePopulatePathname, d as useUniversalContext, t as usePageTransition, u as usePrivateLocation } from "./hooks-BCUm8YC_.js"; import { t as wrapClientComponent } from "./wrap-client-DyCFsAJ7.js"; import { useEffect, useLayoutEffect, useRef, useState } from "react"; import { Fragment, jsx } from "react/jsx-runtime"; //#region private/client/components/history.tsx const HistoryContent = ({ children }) => { const universalContext = useUniversalContext(); const { transitionPage } = usePageTransition(); const { pathname, search, hash } = usePrivateLocation(); const populatedPathname = usePopulatePathname()(pathname); const lastPopulatedPathname = useRef(null); const lastHash = useRef(null); useEffect(() => { const pageChanged = () => { const newLocation = window.location; transitionPage(newLocation.pathname + newLocation.search + newLocation.hash, { updateAddressBar: false }); }; window.addEventListener("popstate", pageChanged); return () => window.removeEventListener("popstate", pageChanged); }, [transitionPage]); useLayoutEffect(() => { if (!lastPopulatedPathname.current) return; if (!universalContext.addressBarInSync) return; history.pushState({}, "", populatedPathname + search + hash); if (hash && lastHash.current !== hash) { document.querySelector(hash)?.scrollIntoView(); return; } if (populatedPathname && lastPopulatedPathname.current !== populatedPathname) { document.documentElement.scrollTop = 0; document.body.scrollTop = 0; } }, [populatedPathname + search + hash]); useLayoutEffect(() => { lastPopulatedPathname.current = populatedPathname; lastHash.current = hash; }, [populatedPathname + search + hash]); return /* @__PURE__ */ jsx(Fragment, { children }); }; const History = ({ children, universalContext }) => { /** * Used for persisting the execution of a query across renders. * * Whenever a query is executed on the client, it is sent to the edge and executed * there, after which the page is re-rendered with the new data. As a result, the * original instance of the `useMutation` hook that ran the query might no longer be * present (for example if the surrounding component was unmounted). In order for its * associated promise to still resolve, we need to persist it across renders. */ const deferredPromises = useRef({}); /** * Used for immediately updating the client-side query string parameters (in the * address bar), while the server is still rendering the respective update for the page. * * This is useful in cases where client-side state is derived from the URL, such as when * using a `?search` query parameter to filter a list of items. In those cases, the URL * can be updated immediately to avoid having to store additional state on the client, * and then the server will process the re-rendering of the page in the meantime. * * We're intentionally and explicitly only doing this for query string parameters and * not for the pathname, because we would otherwise have to require an unpopulated * pathname to be passed to `redirect()` calls, which currently accepts populated * pathnames as well. Only the server can resolve the unpopulated version (which is * essentially the file system path of the page) of a pathname, so we can't do this * update on the client alone. */ const [clientQueryParams, setClientQueryParams] = useState(null); useEffect(() => setClientQueryParams(null), [universalContext.url]); const parsedURL = new URL(universalContext.url); if (clientQueryParams) parsedURL.search = clientQueryParams; return /* @__PURE__ */ jsx(RootClientContext.Provider, { value: { ...universalContext, url: parsedURL.href, setClientQueryParams, deferredPromises }, children: /* @__PURE__ */ jsx(HistoryContent, { children }) }); }; wrapClientComponent(History, "History"); //#endregion export { History as t };