UNPKG

nuqs

Version:

Type-safe search params state manager for React - Like useState, but stored in the URL query string

107 lines (105 loc) 3.94 kB
import { globalThrottleQueue } from "./debounce-CmqzOOem.js"; import { debug, renderQueryString } from "./context-BWo_DoaC.js"; import { resetQueues } from "./reset-BmRuoRYl.js"; import { useCallback, useEffect, useMemo } from "react"; import { useRouter } from "next/compat/router.js"; //#region src/adapters/next/impl.pages.ts function isPagesRouter() { return typeof window.next?.router?.state?.asPath === "string"; } let isNuqsUpdateMutex = false; function onNavigation() { if (isNuqsUpdateMutex) return; resetQueues(); } function useNuqsNextPagesRouterAdapter() { const router = useRouter(); useEffect(() => { router?.events.on("routeChangeStart", onNavigation); router?.events.on("beforeHistoryChange", onNavigation); return () => { router?.events.off("routeChangeStart", onNavigation); router?.events.off("beforeHistoryChange", onNavigation); }; }, []); const searchParams = useMemo(() => { const searchParams$1 = new URLSearchParams(); if (router === null) return searchParams$1; for (const [key, value] of Object.entries(router.query)) if (typeof value === "string") searchParams$1.set(key, value); else if (Array.isArray(value)) for (const v of value) searchParams$1.append(key, v); return searchParams$1; }, [JSON.stringify(router?.query)]); const updateUrl = useCallback((search, options) => { const nextRouter = window.next?.router; const urlParams = extractDynamicUrlParams(nextRouter.pathname, nextRouter.query); const asPath = getAsPathPathname(nextRouter.asPath) + renderQueryString(search) + location.hash; debug("[nuqs next/pages] Updating url: %s", asPath); const method = options.history === "push" ? nextRouter.push : nextRouter.replace; isNuqsUpdateMutex = true; requestAnimationFrame(() => requestAnimationFrame(() => globalThrottleQueue.reset())); method.call(nextRouter, { pathname: nextRouter.pathname, query: { ...urlSearchParamsToObject(search), ...urlParams } }, asPath, { scroll: options.scroll, shallow: options.shallow }).finally(() => { isNuqsUpdateMutex = false; }); }, []); return { searchParams, updateUrl, autoResetQueueOnUpdate: false }; } function getAsPathPathname(asPath) { return asPath.replace(/#.*$/, "").replace(/\?.*$/, ""); } function urlSearchParamsToObject(search) { const out = {}; for (const key of search.keys()) { const values = search.getAll(key); if (values.length === 1) out[key] = values[0]; else if (values.length > 1) out[key] = values; } return out; } /** * Next.js pages router merges dynamic URL params with search params in its * internal state. * However, we need to pass just the URL params to the href part of the router * update functions. * This function finds the dynamic URL params placeholders in the pathname * (eg: `/path/[foo]/[bar]`) and extracts the corresponding values from the * query state object, leaving out any other search params. */ function extractDynamicUrlParams(pathname, values) { const paramNames = /* @__PURE__ */ new Set(); const dynamicRegex = /\[([^\]]+)\]/g; const catchAllRegex = /\[\.{3}([^\]]+)\]$/; const optionalCatchAllRegex = /\[\[\.{3}([^\]]+)\]\]$/; let match; while ((match = dynamicRegex.exec(pathname)) !== null) { const paramName = match[1]; if (paramName) paramNames.add(paramName); } const dynamicValues = Object.fromEntries(Object.entries(values).filter(([key]) => paramNames.has(key))); const matchCatchAll = catchAllRegex.exec(pathname); if (matchCatchAll && matchCatchAll[1]) { const key = matchCatchAll[1]; dynamicValues[key] = values[key] ?? []; } const matchOptionalCatchAll = optionalCatchAllRegex.exec(pathname); if (matchOptionalCatchAll && matchOptionalCatchAll[1]) { const key = matchOptionalCatchAll[1]; dynamicValues[key] = values[key] ?? []; } return dynamicValues; } //#endregion export { isPagesRouter, useNuqsNextPagesRouterAdapter }; //# sourceMappingURL=impl.pages-D9M0Y18b.js.map