"use strict"; 'use client'; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.store = void 0; exports.useStore = useStore; exports.useRouteInfo = useRouteInfo; const native_1 = require("@react-navigation/native"); const expo_constants_1 = __importDefault(require("expo-constants")); const react_1 = require("react"); const react_native_1 = require("react-native"); const extractPathFromURL_1 = require("../fork/extractPathFromURL"); const getStateFromPath_forks_1 = require("../fork/getStateFromPath-forks"); const getLinkingConfig_1 = require("../getLinkingConfig"); const getReactNavigationConfig_1 = require("../getReactNavigationConfig"); const getRoutes_1 = require("../getRoutes"); const routeInfo_1 = require("./routeInfo"); const href_1 = require("../link/href"); const useScreens_1 = require("../useScreens"); const PreviewRouteContext_1 = require("../link/preview/PreviewRouteContext"); const url_1 = require("../utils/url"); const SplashScreen = __importStar(require("../views/Splash")); const storeRef = { current: {}, }; const routeInfoCache = new WeakMap(); const routeInfoValuesCache = new Map(); let splashScreenAnimationFrame; let hasAttemptedToHideSplash = false; exports.store = { shouldShowTutorial() { return !storeRef.current.routeNode && process.env.NODE_ENV === 'development'; }, get state() { return storeRef.current.state; }, get navigationRef() { return storeRef.current.navigationRef; }, get routeNode() { return storeRef.current.routeNode; }, getRouteInfo() { return storeRef.current.routeInfo || routeInfo_1.defaultRouteInfo; }, get redirects() { return storeRef.current.redirects || []; }, get rootComponent() { return storeRef.current.rootComponent; }, getStateForHref(href, options) { href = (0, href_1.resolveHref)(href); href = (0, href_1.resolveHrefStringWithSegments)(href, exports.store.getRouteInfo(), options); return this.linking?.getStateFromPath(href, this.linking.config); }, get linking() { return storeRef.current.linking; }, setFocusedState(state) { const routeInfo = getCachedRouteInfo(state); storeRef.current.routeInfo = routeInfo; }, onReady() { if (!hasAttemptedToHideSplash) { hasAttemptedToHideSplash = true; // NOTE(EvanBacon): `navigationRef.isReady` is sometimes not true when state is called initially. splashScreenAnimationFrame = requestAnimationFrame(() => { SplashScreen._internal_maybeHideAsync?.(); }); } }, onStateChange(newState) { if (!newState) { return; } if (process.env.NODE_ENV === 'development') { let isStale = false; let state = newState; while (!isStale && state) { isStale = state.stale; state = state.routes?.['index' in state && typeof state.index === 'number' ? state.index : state.routes.length - 1]?.state; } if (isStale) { // This should never happen, as onStateChange should provide a full state. However, adding this check to catch any undocumented behavior. console.error('Detected stale state in onStateChange. This is likely a bug in Expo Router.'); } } storeRef.current.state = newState; storeRef.current.routeInfo = getCachedRouteInfo(newState); for (const callback of routeInfoSubscribers) { callback(); } }, assertIsReady() { if (!storeRef.current.navigationRef.isReady()) { throw new Error('Attempted to navigate before mounting the Root Layout component. Ensure the Root Layout component is rendering a Slot, or other navigator on the first render.'); } }, }; function useStore(context, linkingConfigOptions, serverUrl) { const navigationRef = (0, native_1.useNavigationContainerRef)(); const config = expo_constants_1.default.expoConfig?.extra?.router; let linking; let rootComponent = react_1.Fragment; let initialState; const routeNode = (0, getRoutes_1.getRoutes)(context, { ...config, skipGenerated: true, ignoreEntryPoints: true, platform: react_native_1.Platform.OS, preserveRedirectAndRewrites: true, }); const redirects = [config?.redirects, config?.rewrites] .filter(Boolean) .flat() .map((route) => { return [ (0, getStateFromPath_forks_1.routePatternToRegex)((0, getReactNavigationConfig_1.parseRouteSegments)(route.source)), route, (0, url_1.shouldLinkExternally)(route.destination), ]; }); if (routeNode) { // We have routes, so get the linking config and the root component linking = (0, getLinkingConfig_1.getLinkingConfig)(routeNode, context, () => exports.store.getRouteInfo(), { metaOnly: linkingConfigOptions.metaOnly, serverUrl, redirects, skipGenerated: config?.skipGenerated ?? false, sitemap: config?.sitemap ?? true, notFound: config?.notFound ?? true, }); rootComponent = (0, useScreens_1.getQualifiedRouteComponent)(routeNode); // By default React Navigation is async and does not render anything in the first pass as it waits for `getInitialURL` // This will cause static rendering to fail, which once performs a single pass. // If the initialURL is a string, we can prefetch the state and routeInfo, skipping React Navigation's async behavior. const initialURL = linking?.getInitialURL?.(); if (typeof initialURL === 'string') { let initialPath = (0, extractPathFromURL_1.extractExpoPathFromURL)(linking.prefixes, initialURL); // It does not matter if the path starts with a `/` or not, but this keeps the behavior consistent if (!initialPath.startsWith('/')) initialPath = '/' + initialPath; initialState = linking.getStateFromPath(initialPath, linking.config); const initialRouteInfo = (0, routeInfo_1.getRouteInfoFromState)(initialState); routeInfoCache.set(initialState, initialRouteInfo); routeInfoValuesCache.set(JSON.stringify(initialRouteInfo), initialRouteInfo); } } else { // Only error in production, in development we will show the onboarding screen if (process.env.NODE_ENV === 'production') { throw new Error('No routes found'); } // In development, we will show the onboarding screen rootComponent = react_1.Fragment; } if (react_native_1.Platform.OS === 'android' && storeRef.current.state && storeRef.current.context === context) { initialState = storeRef.current.state; } storeRef.current = { navigationRef, routeNode, config, rootComponent, linking, redirects, state: initialState, context, }; if (initialState) { storeRef.current.routeInfo = getCachedRouteInfo(initialState); } (0, react_1.useEffect)(() => { return () => { // listener(); if (splashScreenAnimationFrame) { cancelAnimationFrame(splashScreenAnimationFrame); splashScreenAnimationFrame = undefined; } }; }); return exports.store; } const routeInfoSubscribers = new Set(); const routeInfoSubscribe = (callback) => { routeInfoSubscribers.add(callback); return () => { routeInfoSubscribers.delete(callback); }; }; function useRouteInfo() { const routeInfo = (0, react_1.useSyncExternalStore)(routeInfoSubscribe, exports.store.getRouteInfo, exports.store.getRouteInfo); const { isPreview, segments, params, pathname } = (0, PreviewRouteContext_1.usePreviewInfo)(); if (isPreview) { return { pathname: pathname ?? '', segments: segments ?? [], unstable_globalHref: '', params: params ?? {}, searchParams: new URLSearchParams(), pathnameWithParams: pathname ?? '', isIndex: false, }; } return routeInfo; } function getCachedRouteInfo(state) { let routeInfo = routeInfoCache.get(state); if (!routeInfo) { routeInfo = (0, routeInfo_1.getRouteInfoFromState)(state); const routeInfoString = JSON.stringify(routeInfo); // Using cached values to avoid re-renders, to increase the chance that the object reference is the same const cachedRouteInfo = routeInfoValuesCache.get(routeInfoString); if (cachedRouteInfo) { routeInfo = cachedRouteInfo; } else { routeInfoValuesCache.set(routeInfoString, routeInfo); } routeInfoCache.set(state, routeInfo); } return routeInfo; } //# sourceMappingURL=router-store.js.map