UNPKG

one

Version:

One is a new React Framework that makes Vite serve both native and web.

786 lines (785 loc) 29.8 kB
import { StackActions } from "@react-navigation/native"; import { Fragment, startTransition, useDeferredValue, useSyncExternalStore } from "react"; import { Platform } from "react-native-web"; import { devtoolsRegistry } from "../devtools/registry.mjs"; import { resolveHref } from "../link/href.mjs"; import { openExternalURL } from "../link/openExternalURL.mjs"; import { resolve } from "../link/path.mjs"; import { checkBlocker } from "../useBlocker.mjs"; import { assertIsReady } from "../utils/assertIsReady.mjs"; import { getLoaderPath, getPreloadCSSPath, getPreloadPath } from "../utils/cleanUrl.mjs"; import { dynamicImport } from "../utils/dynamicImport.mjs"; import { isVersionStale } from "../skewProtection.mjs"; import { shouldLinkExternally } from "../utils/url.mjs"; import { ParamValidationError, RouteValidationError, validateParams as runValidateParams } from "../validateParams.mjs"; import { extractParamsFromState, extractPathnameFromHref, extractSearchFromHref, findRouteNodeFromState, findAllRouteNodesFromState } from "./findRouteNode.mjs"; import { getRouteInfo } from "./getRouteInfo.mjs"; import { getRoutes } from "./getRoutes.mjs"; import { setLastAction } from "./lastAction.mjs"; import { getResolvedLinking, resetLinking, setupLinking } from "./linkingConfig.mjs"; import { sortRoutes } from "./sortRoutes.mjs"; import { getQualifiedRouteComponent } from "./useScreens.mjs"; import { preloadRouteModules } from "./useViteRoutes.mjs"; import { getNavigateAction } from "./utils/getNavigateAction.mjs"; import { setClientMatches } from "../useMatches.mjs"; import { findInterceptRoute, setNavigationType, updateURLWithoutNavigation, storeInterceptState } from "./interceptRoutes.mjs"; import { setSlotState } from "../views/Navigator.mjs"; import { clearNotFoundState, findNearestNotFoundRoute, setNotFoundState } from "../notFoundState.mjs"; let routeNode = null; let rootComponent; const protectedRouteRegistry = /* @__PURE__ */new Map(); function registerProtectedRoutes(contextKey, protectedScreens) { if (protectedScreens.size === 0) protectedRouteRegistry.delete(contextKey);else protectedRouteRegistry.set(contextKey, protectedScreens); } function unregisterProtectedRoutes(contextKey) { protectedRouteRegistry.delete(contextKey); } function isRouteProtected(href) { const normalizedHref = href.replace(/^\/+|\/+$/g, ""); for (const [contextKey, protectedScreens] of protectedRouteRegistry) { const normalizedContextKey = contextKey.replace(/^\/+|\/+$/g, ""); if (normalizedHref.startsWith(normalizedContextKey)) { const routeName = normalizedHref.slice(normalizedContextKey.length).replace(/^\//, "").split("/")[0] || "index"; const normalizedRouteName = routeName.replace(/\/index$/, ""); if (protectedScreens.has(routeName) || protectedScreens.has(normalizedRouteName)) return true; } } return false; } let hasAttemptedToHideSplash = false; let initialState; let rootState; let initialPathname; let lastIntendedPathname; let nextState; let routeInfo; let splashScreenAnimationFrame; let pendingNavigationPathname; let pendingNavigationAction; let navigationRef = null; const rootStateSubscribers = /* @__PURE__ */new Set(); const loadingStateSubscribers = /* @__PURE__ */new Set(); const storeSubscribers = /* @__PURE__ */new Set(); let currentMatches = []; let validationState = { status: "idle" }; const validationStateSubscribers = /* @__PURE__ */new Set(); function subscribeToValidationState(subscriber) { validationStateSubscribers.add(subscriber); return () => validationStateSubscribers.delete(subscriber); } function setValidationState(state) { validationState = state; for (const subscriber of validationStateSubscribers) subscriber(state); if (state.status === "error" && state.error) window.dispatchEvent(new CustomEvent("one-validation-error", { detail: { error: { message: state.error.message, name: state.error.name, stack: state.error.stack }, href: state.lastValidatedHref, timestamp: Date.now() } })); } function getValidationState() { return validationState; } function useValidationState() { return useSyncExternalStore(subscribeToValidationState, getValidationState, getValidationState); } let cachedRouteNode = null; let cachedRootComponent = null; let cachedContext = null; function initialize(context, ref, initialLocation, linking) { cleanUpState(); if (context !== cachedContext || !cachedRouteNode) { cachedRouteNode = getRoutes(context, { ignoreEntryPoints: true, platform: Platform.OS }); cachedRootComponent = cachedRouteNode ? getQualifiedRouteComponent(cachedRouteNode) : Fragment; cachedContext = context; } routeNode = cachedRouteNode; rootComponent = cachedRootComponent || Fragment; if (!routeNode && process.env.NODE_ENV === "production") throw new Error("No routes found"); if (process.env.ONE_DEBUG_ROUTER && routeNode) { const formatRouteTree = (node, indent = "", isLast = true) => { const prefix = indent + (isLast ? "└─ " : "├─ "); const childIndent = indent + (isLast ? " " : "│ "); const dynamicBadge = node.dynamic ? ` [${node.dynamic.map(d => d.name).join(", ")}]` : ""; const typeBadge = node.type !== "layout" ? ` (${node.type})` : ""; const slotsBadge = node.slots?.size ? ` {@${Array.from(node.slots.keys()).join(", @")}}` : ""; let line = `${prefix}${node.route || "/"}${dynamicBadge}${typeBadge}${slotsBadge}`; const visibleChildren = node.children.filter(child => !child.internal); for (let i = 0; i < visibleChildren.length; i++) { const child = visibleChildren[i]; const childIsLast = i === visibleChildren.length - 1; line += "\n" + formatRouteTree(child, childIndent, childIsLast); } return line; }; console.info(`[one] \u{1F4CD} Route structure: ${formatRouteTree(routeNode)}`); if (routeNode.slots?.size) { console.info(`[one] \u{1F4E6} Slots on root layout:`); for (const [slotName, slotConfig] of routeNode.slots) console.info(` @${slotName}:`, { defaultRoute: slotConfig.defaultRoute?.route, interceptRoutes: slotConfig.interceptRoutes.map(r => ({ route: r.route, intercept: r.intercept })) }); } } navigationRef = ref; setupLinkingAndRouteInfo(initialLocation, linking); subscribeToNavigationChanges(); } function cleanUpState() { initialState = void 0; initialPathname = void 0; lastIntendedPathname = void 0; rootState = void 0; nextState = void 0; routeInfo = void 0; pendingNavigationPathname = void 0; pendingNavigationAction = void 0; resetLinking(); rootStateSubscribers.clear(); storeSubscribers.clear(); } function setupLinkingAndRouteInfo(initialLocation, linking) { initialState = setupLinking(routeNode, initialLocation, linking); initialPathname = initialLocation?.pathname ?? (typeof document !== "undefined" ? window.location.pathname : void 0); if (initialState) { rootState = initialState; routeInfo = getRouteInfo(initialState); } else routeInfo = { unstable_globalHref: "", pathname: "", isIndex: false, params: {}, segments: [] }; } function handleNavigationContainerStateChange(navState) { if (!navState) return; let state = { ...navState }; if (state.key) { if (hashes[state.key]) { state.hash = hashes[state.key]; delete hashes[state.key]; } } if (!hasAttemptedToHideSplash) { hasAttemptedToHideSplash = true; splashScreenAnimationFrame = requestAnimationFrame(() => {}); } if (shouldKeepPendingNavigationState(state)) return; if (nextOptions) { state = { ...state, linkOptions: nextOptions }; nextOptions = null; } let shouldUpdateSubscribers = nextState === state; nextState = void 0; if (state && state !== rootState) { updateState(state, void 0); shouldUpdateSubscribers = true; } if (shouldUpdateSubscribers) startTransition(() => { for (const subscriber of rootStateSubscribers) subscriber(state); }); } function subscribeToNavigationChanges() { startTransition(() => { updateSnapshot(); for (const subscriber of storeSubscribers) subscriber(); }); } function navigate(url, options) { return linkTo(resolveHref(url), "NAVIGATE", options); } function push(url, options) { return linkTo(resolveHref(url), "PUSH", options); } function dismiss(count) { if (process.env.ONE_DEBUG_ROUTER) console.info(`[one] \u{1F519} dismiss${count ? ` (${count})` : ""}`); navigationRef?.dispatch(StackActions.pop(count)); } function replace(url, options) { return linkTo(resolveHref(url), "REPLACE", options); } function setParams(params = {}) { assertIsReady(navigationRef); return navigationRef?.current?.setParams( // @ts-expect-error params); } function dismissAll() { if (process.env.ONE_DEBUG_ROUTER) console.info(`[one] \u{1F519} dismissAll`); navigationRef?.dispatch(StackActions.popToTop()); } function goBack() { if (process.env.ONE_DEBUG_ROUTER) console.info(`[one] \u{1F519} goBack`); assertIsReady(navigationRef); navigationRef?.current?.goBack(); } function canGoBack() { if (!navigationRef.isReady()) return false; return navigationRef?.current?.canGoBack() ?? false; } function canDismiss() { let state = rootState; while (state) { if (state.type === "stack" && state.routes.length > 1) return true; if (state.index === void 0) return false; state = state.routes?.[state.index]?.state; } return false; } function getSortedRoutes() { if (!routeNode) throw new Error("No routes"); return routeNode.children.filter(route => !route.internal).sort(sortRoutes); } function updateState(state, nextStateParam = state) { rootState = state; nextState = nextStateParam; const nextRouteInfo = getRouteInfo(state); if (pendingNavigationPathname === nextRouteInfo.pathname) pendingNavigationPathname = void 0; if (!deepEqual(routeInfo, nextRouteInfo)) { if (process.env.ONE_DEBUG_ROUTER) { const from = routeInfo?.pathname || "(initial)"; const to = nextRouteInfo.pathname; const params = Object.keys(nextRouteInfo.params || {}).length ? nextRouteInfo.params : void 0; console.info(`[one] \u{1F9ED} ${from} \u2192 ${to}`, params ? { params } : ""); } routeInfo = nextRouteInfo; } if (process.env.NODE_ENV === "development" && typeof window !== "undefined") { window.__oneDevtools = { routeInfo: nextRouteInfo, rootState: state, routeNode, getRoutes: () => routeNode?.children || [], getLoaderTimingHistory: () => devtoolsRegistry.getLoaderTimingHistory?.() ?? [], getPreloadHistory }; window.dispatchEvent(new CustomEvent("one-route-change", { detail: nextRouteInfo })); } } function consumePendingNavigationAction() { const action = pendingNavigationAction; pendingNavigationAction = void 0; return action; } function subscribeToRootState(subscriber) { rootStateSubscribers.add(subscriber); return () => { rootStateSubscribers.delete(subscriber); }; } function notifyRootStateSubscribers(state) { for (const subscriber of rootStateSubscribers) subscriber(state); } function subscribeToStore(subscriber) { storeSubscribers.add(subscriber); return () => { storeSubscribers.delete(subscriber); }; } function subscribeToLoadingState(subscriber) { loadingStateSubscribers.add(subscriber); return () => { loadingStateSubscribers.delete(subscriber); }; } function setLoadingState(state) { startTransition(() => { for (const listener of loadingStateSubscribers) listener(state); }); } let currentSnapshot = null; function updateSnapshot() { currentSnapshot = getSnapshot(); } function snapshot() { return currentSnapshot; } function getSnapshot() { return { linkTo, routeNode, rootComponent, linking: getResolvedLinking(), hasAttemptedToHideSplash, initialState, rootState, nextState, routeInfo, splashScreenAnimationFrame, navigationRef, rootStateSubscribers, storeSubscribers }; } function rootStateSnapshot() { return rootState; } function routeInfoSnapshot() { return routeInfo; } function normalizePathname(pathname) { return pathname.length > 1 && pathname.endsWith("/") ? pathname.slice(0, -1) : pathname; } function getBrowserPathname() { if (typeof document === "undefined") return void 0; return normalizePathname(window.location.pathname); } function shouldKeepPendingNavigationState(currentState) { if (!pendingNavigationPathname) return false; return getRouteInfo(currentState).pathname !== pendingNavigationPathname; } function shouldPreserveInitialRouteInfo(currentState) { if (!initialState || !routeInfo?.pathname) return false; const nextPathname = getRouteInfo(currentState).pathname; if (nextPathname === routeInfo.pathname) return false; if (nextPathname && nextPathname === pendingNavigationPathname) return false; const browserPathname = getBrowserPathname(); if (nextPathname && browserPathname && nextPathname === browserPathname) return false; return true; } function useOneRouter() { return useDeferredValue(useSyncExternalStore(subscribeToStore, snapshot, snapshot)); } function syncStoreRootState() { if (!navigationRef) throw new Error(`No navigationRef, possible duplicate One dep`); if (navigationRef.isReady()) { const currentState = navigationRef.getRootState(); if (rootState !== currentState) { if (shouldKeepPendingNavigationState(currentState)) return; if (shouldPreserveInitialRouteInfo(currentState)) return; updateState(currentState); } } } function useStoreRootState() { syncStoreRootState(); return useDeferredValue(useSyncExternalStore(subscribeToRootState, rootStateSnapshot, rootStateSnapshot)); } function useStoreRouteInfo() { syncStoreRootState(); return useSyncExternalStore(subscribeToRootState, routeInfoSnapshot, routeInfoSnapshot); } function cleanup() { if (splashScreenAnimationFrame) cancelAnimationFrame(splashScreenAnimationFrame); } const preloadingLoader = {}; async function doPreloadDev(href) { if (process.env.NODE_ENV === "development") { const startTime = performance.now(); const normalizedPath = normalizeLoaderPath(href); try { const loaderJSUrl = getLoaderPath(href, true); const moduleLoadStart = performance.now(); const modulePromise = dynamicImport(loaderJSUrl); if (!modulePromise) return null; const module = await modulePromise.catch(() => null); const moduleLoadTime = performance.now() - moduleLoadStart; if (!module?.loader) return null; const executionStart = performance.now(); const result = await module.loader(); const executionTime = performance.now() - executionStart; const totalTime = performance.now() - startTime; if (result?.__oneRedirect) return result; devtoolsRegistry.recordLoaderTiming?.({ path: normalizedPath, startTime, moduleLoadTime, executionTime, totalTime, source: "preload" }); return result ?? null; } catch (err) { const totalTime = performance.now() - startTime; devtoolsRegistry.recordLoaderTiming?.({ path: normalizedPath, startTime, totalTime, error: err instanceof Error ? err.message : String(err), source: "preload" }); if (process.env.ONE_DEBUG_ROUTER) console.warn(`[one] dev preload failed for ${href}:`, err); return null; } } } async function doPreload(href) { const preloadPath = getPreloadPath(href); const loaderPath = getLoaderPath(href); const cssPreloadPath = getPreloadCSSPath(href); recordPreloadStart(href); try { const [_preload, cssPreloadModule, loader] = await Promise.all([dynamicImport(preloadPath)?.catch(err => { recordPreloadError(href, err instanceof Error ? err.message : String(err)); return null; }), dynamicImport(cssPreloadPath)?.catch(() => null) ?? Promise.resolve(null), dynamicImport(loaderPath)?.catch(() => null) ?? Promise.resolve(null), preloadRouteModules(href)]); const hasCss = !!cssPreloadModule?.injectCSS; if (hasCss) cssInjectFunctions[href] = cssPreloadModule.injectCSS; if (!!!loader?.loader) { recordPreloadComplete(href, false, hasCss); return null; } const result = await loader.loader(); if (result?.__oneRedirect) return result; recordPreloadComplete(href, true, hasCss); return result ?? null; } catch (err) { const errorMessage = err instanceof Error ? err.message : String(err); console.error(`[one] preload error for ${href}:`, err); recordPreloadError(href, errorMessage); return null; } } const preloadedLoaderData = {}; const cssInjectFunctions = {}; const preloadHistory = []; const MAX_PRELOAD_HISTORY = 30; function recordPreloadStart(href) { if (process.env.NODE_ENV !== "development") return; const existing = preloadHistory.find(p => p.href === href); if (existing) { existing.status = "loading"; existing.startTime = performance.now(); return; } preloadHistory.unshift({ href, status: "loading", startTime: performance.now(), hasLoader: false, hasCss: false }); if (preloadHistory.length > MAX_PRELOAD_HISTORY) preloadHistory.pop(); dispatchPreloadEvent(); } function recordPreloadComplete(href, hasLoader, hasCss) { if (process.env.NODE_ENV !== "development") return; const entry = preloadHistory.find(p => p.href === href); if (entry) { entry.status = "loaded"; entry.endTime = performance.now(); entry.hasLoader = hasLoader; entry.hasCss = hasCss; } dispatchPreloadEvent(); } function recordPreloadError(href, error) { if (process.env.NODE_ENV !== "development") return; const entry = preloadHistory.find(p => p.href === href); if (entry) { entry.status = "error"; entry.endTime = performance.now(); entry.error = error; } dispatchPreloadEvent(); } function dispatchPreloadEvent() { window.dispatchEvent(new CustomEvent("one-preload-update")); } function getPreloadHistory() { return preloadHistory; } function preloadRoute(href, injectCSS = false) { if (process.env.NODE_ENV === "development") { const normalizedHref = normalizeLoaderPath(href); if (!preloadingLoader[normalizedHref]) preloadingLoader[normalizedHref] = doPreloadDev(href).then(data => { preloadedLoaderData[normalizedHref] = data; return data; }); return preloadingLoader[normalizedHref]; } if (!preloadingLoader[href]) preloadingLoader[href] = doPreload(href).then(data => { preloadedLoaderData[href] = data; return data; }); if (injectCSS) return preloadingLoader[href]?.then(async data => { const inject = cssInjectFunctions[href]; if (inject) await Promise.race([inject(), new Promise(r => setTimeout(r, 800))]); return data; }); return preloadingLoader[href]; } function normalizeLoaderPath(href) { return new URL(href, "http://example.com").pathname.replace(/\/index$/, "").replace(/\/$/, "") || "/"; } function buildClientMatches(href, matchingNode, params, loaderData) { const pathname = extractPathnameFromHref(href); const routeId = matchingNode?.contextKey || pathname; const layoutMatches = currentMatches.filter(m => m.routeId.includes("_layout")); const pageMatch = { routeId, pathname, params, loaderData }; return [...layoutMatches, pageMatch]; } function initClientMatches(matches) { currentMatches = matches; setClientMatches(matches); } async function linkTo(href, event, options) { if (process.env.ONE_DEBUG_ROUTER) console.info(`[one] \u{1F517} ${event || "NAVIGATE"} ${href}`); setNavigationType("soft"); clearNotFoundState(); if (href[0] === "#") return; if (shouldLinkExternally(href)) { openExternalURL(href); return; } if (isVersionStale()) { window.location.href = href; return; } if (checkBlocker(href, event === "REPLACE" ? "replace" : "push")) return; if (isRouteProtected(href)) return; const currentLayoutNode = routeNode; const currentPath = routeInfo?.pathname || "/"; const interceptResult = findInterceptRoute(href, currentLayoutNode, currentPath); if (interceptResult) { const { interceptRoute, slotName, layoutContextKey, params: params2 } = interceptResult; const scopedSlotKey = `${layoutContextKey}:${slotName}`; storeInterceptState(scopedSlotKey, interceptRoute, params2); updateURLWithoutNavigation(href); setSlotState(scopedSlotKey, { activeRouteKey: interceptRoute.contextKey, activeRouteNode: interceptRoute, params: params2, isIntercepted: true }); return; } assertIsReady(navigationRef); const current = navigationRef.current; if (current == null) throw new Error("Couldn't find a navigation object. Is your component inside NavigationContainer?"); const linking = getResolvedLinking(); if (!linking) throw new Error("Attempted to link to route when no routes are present"); setLastAction(); if (href === ".." || href === "../") { current.goBack(); return; } if (href.startsWith(".")) { let base = routeInfo?.segments?.map(segment => { if (!segment.startsWith("[")) return segment; if (segment.startsWith("[...")) { segment = segment.slice(4, -1); const params2 = routeInfo?.params?.[segment]; if (Array.isArray(params2)) return params2.join("/"); return params2?.split(",")?.join("/") ?? ""; } segment = segment.slice(1, -1); return routeInfo?.params?.[segment]; }).filter(Boolean).join("/") ?? "/"; if (!routeInfo?.isIndex) base += "/.."; href = resolve(base, href); } const state = linking.getStateFromPath(href, linking.config); if (!state || state.routes.length === 0) { console.error("Could not generate a valid navigation state for the given path: " + href); console.error(`linking.config`, linking.config); console.error(`routes`, getSortedRoutes()); return; } setLoadingState("loading"); const normalizedPreloadPath = normalizeLoaderPath(href); if (!(normalizedPreloadPath in preloadedLoaderData) && !(href in preloadedLoaderData)) await preloadRoute(href, true);else if (process.env.NODE_ENV !== "development") { const inject = cssInjectFunctions[href]; if (inject) inject().catch(() => {}); } const preloadResult = preloadedLoaderData[normalizedPreloadPath]; if (preloadResult?.__oneRedirect) { const redirectTarget = preloadResult.__oneRedirect; delete preloadedLoaderData[normalizedPreloadPath]; delete preloadingLoader[normalizedPreloadPath]; delete preloadedLoaderData[href]; delete preloadingLoader[href]; setLoadingState("loaded"); linkTo(redirectTarget, "REPLACE"); return; } if (preloadResult?.__oneError === 404) { delete preloadedLoaderData[normalizedPreloadPath]; delete preloadingLoader[normalizedPreloadPath]; delete preloadedLoaderData[href]; delete preloadingLoader[href]; setLoadingState("loaded"); const notFoundRoute = findNearestNotFoundRoute(href, routeNode); setNotFoundState({ notFoundPath: preloadResult.__oneNotFoundPath || "/+not-found", notFoundRouteNode: notFoundRoute || void 0, originalPath: href }); return; } const matchingRouteNode = findRouteNodeFromState(state, routeNode); if (matchingRouteNode?.loadRoute) { setValidationState({ status: "validating", lastValidatedHref: href }); try { const loadedRoute = matchingRouteNode.loadRoute(); const params2 = extractParamsFromState(state); const search = extractSearchFromHref(href); const pathname = extractPathnameFromHref(href); if (loadedRoute.validateParams) runValidateParams(loadedRoute.validateParams, params2); if (loadedRoute.validateRoute) { const validationResult = await loadedRoute.validateRoute({ params: params2, search, pathname, href }); if (validationResult && !validationResult.valid) { const error = new RouteValidationError(validationResult.error || "Route validation failed", validationResult.details); setValidationState({ status: "error", error, lastValidatedHref: href }); throw error; } } setValidationState({ status: "valid", lastValidatedHref: href }); } catch (error) { if (error && typeof error.then === "function") { await error.catch(() => {}); setValidationState({ status: "valid", lastValidatedHref: href }); } else if (error instanceof ParamValidationError || error instanceof RouteValidationError) { setValidationState({ status: "error", error, lastValidatedHref: href }); throw error; } else throw error; } } const loaderData = preloadedLoaderData[normalizeLoaderPath(href)]; const params = extractParamsFromState(state); const newMatches = buildClientMatches(href, matchingRouteNode, params, loaderData); currentMatches = newMatches; setClientMatches(newMatches); const currentRootState = navigationRef.getRootState(); const hash = href.indexOf("#"); if (currentRootState.key && hash > 0) hashes[currentRootState.key] = href.slice(hash); nextOptions = options ?? null; pendingNavigationPathname = normalizePathname(extractPathnameFromHref(href)); pendingNavigationAction = event === "PUSH" || event === "REPLACE" || event === "NAVIGATE" ? event : void 0; lastIntendedPathname = pendingNavigationPathname; const freshRootState = navigationRef.getRootState(); const currentRouteBeforeDispatch = navigationRef.getCurrentRoute(); if (event === "REPLACE") { const targetPathname = pendingNavigationPathname; const optimisticState = nextOptions ? { ...state, linkOptions: nextOptions } : state; updateState(optimisticState); pendingNavigationPathname = targetPathname; notifyRootStateSubscribers(optimisticState); navigationRef.resetRoot(state); } else { const action = getNavigateAction(state, freshRootState, event); const targetName = action.payload?.name; const isGroupTarget = typeof targetName === "string" && targetName.startsWith("(") && targetName.endsWith(")"); const hasFreshRootState = freshRootState.type === "stack"; const isRootTarget = action.target === freshRootState.key; const currentFocusedRoute = freshRootState.routes[freshRootState.index]; const currentFocusedName = currentFocusedRoute?.name; if (isRootTarget && isGroupTarget && hasFreshRootState) { const targetRoute = state.routes[state.routes.length - 1]; const targetRootName = targetRoute.name; if (currentFocusedName === targetRootName) { const routes = [...freshRootState.routes]; routes[freshRootState.index] = { ...targetRoute, key: currentFocusedRoute?.key ?? targetRoute.key }; navigationRef.resetRoot({ ...freshRootState, routes }); } else { const existingTargetRoute = freshRootState.routes.find(route => route.name === targetRootName); const existingRoutes = freshRootState.routes.filter(route => route.name !== targetRootName); const nextRootState = { ...freshRootState, routes: [...existingRoutes, { ...targetRoute, key: existingTargetRoute?.key ?? `${targetRootName}-${freshRootState.key}` }], index: existingRoutes.length }; navigationRef.resetRoot(nextRootState); } } else navigationRef.dispatch(action); } let warningTm; const interval = setInterval(() => { if (currentRouteBeforeDispatch !== navigationRef.getCurrentRoute()) setTimeout(() => { setLoadingState("loaded"); }); clearTimeout(warningTm); clearTimeout(interval); }, 16); if (process.env.NODE_ENV === "development") warningTm = setTimeout(() => { console.warn(`Routing took more than 8 seconds`); }, 1e3); } const hashes = {}; let nextOptions = null; function deepEqual(a, b) { if (a === b) return true; if (Array.isArray(a) && Array.isArray(b)) { if (a.length !== b.length) return false; for (let i = 0; i < a.length; i++) if (!deepEqual(a[i], b[i])) return false; return true; } if (typeof a === "object" && typeof b === "object") { const keysA = Object.keys(a); const keysB = Object.keys(b); if (keysA.length !== keysB.length) return false; for (const key of keysA) if (!deepEqual(a[key], b[key])) return false; return true; } return false; } export { canDismiss, canGoBack, cleanup, consumePendingNavigationAction, dismiss, dismissAll, getPreloadHistory, getSortedRoutes, getValidationState, goBack, handleNavigationContainerStateChange, hasAttemptedToHideSplash, initClientMatches, initialPathname, initialState, initialize, isRouteProtected, lastIntendedPathname, linkTo, navigate, navigationRef, preloadRoute, preloadedLoaderData, preloadingLoader, push, registerProtectedRoutes, replace, rootComponent, rootState, rootStateSnapshot, routeInfo, routeInfoSnapshot, routeNode, setLoadingState, setParams, setValidationState, snapshot, subscribeToLoadingState, subscribeToRootState, subscribeToStore, subscribeToValidationState, unregisterProtectedRoutes, updateState, useOneRouter, useStoreRootState, useStoreRouteInfo, useValidationState }; //# sourceMappingURL=router.mjs.map